]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfsd: use workqueue enable/disable APIs for v4_end_grace sync
authorNeilBrown <neil@brown.name>
Sat, 13 Dec 2025 18:42:00 +0000 (13:42 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 26 Jan 2026 15:10:58 +0000 (10:10 -0500)
"nfsd: provide locking for v4_end_grace" introduced a
client_tracking_active flag protected by nn->client_lock to prevent
the laundromat from being scheduled before client tracking
initialization or after shutdown begins. That commit is suitable for
backporting to LTS kernels that predate commit 86898fa6b8cd
("workqueue: Implement disable/enable for (delayed) work items").

However, the workqueue subsystem in recent kernels provides
enable_delayed_work() and disable_delayed_work_sync() for this
purpose. Using this mechanism enable us to remove the
client_tracking_active flag and associated spinlock operations
while preserving the same synchronization guarantees, which is
a cleaner long-term approach.

Signed-off-by: NeilBrown <neil@brown.name>
Tested-by: Li Lingfeng <lilingfeng3@huawei.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/netns.h
fs/nfsd/nfs4state.c

index fe8338735e7cc599a2b6aebbea3ec3e71b07f636..d83c68872c4c3e53d9d251e93dcdcbdeb2aea6a9 100644 (file)
@@ -67,7 +67,6 @@ struct nfsd_net {
        struct lock_manager nfsd4_manager;
        bool grace_ended;
        bool grace_end_forced;
-       bool client_tracking_active;
        time64_t boot_time;
 
        struct dentry *nfsd_client_dir;
index 96e19817cd6bb4cfe38e5d49b2cf3381d655ed47..4a896c7b494fcfe4b7ec5e89c26475656a03d79f 100644 (file)
@@ -6637,14 +6637,14 @@ bool nfsd4_force_end_grace(struct nfsd_net *nn)
 {
        if (!nn->client_tracking_ops)
                return false;
-       spin_lock(&nn->client_lock);
-       if (nn->grace_ended || !nn->client_tracking_active) {
-               spin_unlock(&nn->client_lock);
+       if (READ_ONCE(nn->grace_ended))
                return false;
-       }
+       /* laundromat_work must be initialised now, though it might be disabled */
        WRITE_ONCE(nn->grace_end_forced, true);
+       /* mod_delayed_work() doesn't queue work after
+        * nfs4_state_shutdown_net() has called disable_delayed_work_sync()
+        */
        mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
-       spin_unlock(&nn->client_lock);
        return true;
 }
 
@@ -8980,7 +8980,6 @@ static int nfs4_state_create_net(struct net *net)
        nn->boot_time = ktime_get_real_seconds();
        nn->grace_ended = false;
        nn->grace_end_forced = false;
-       nn->client_tracking_active = false;
        nn->nfsd4_manager.block_opens = true;
        INIT_LIST_HEAD(&nn->nfsd4_manager.list);
        INIT_LIST_HEAD(&nn->client_lru);
@@ -8995,6 +8994,8 @@ static int nfs4_state_create_net(struct net *net)
        INIT_LIST_HEAD(&nn->blocked_locks_lru);
 
        INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
+       /* Make sure this cannot run until client tracking is initialised */
+       disable_delayed_work(&nn->laundromat_work);
        INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
        get_net(net);
 
@@ -9062,9 +9063,7 @@ nfs4_state_start_net(struct net *net)
        locks_start_grace(net, &nn->nfsd4_manager);
        nfsd4_client_tracking_init(net);
        /* safe for laundromat to run now */
-       spin_lock(&nn->client_lock);
-       nn->client_tracking_active = true;
-       spin_unlock(&nn->client_lock);
+       enable_delayed_work(&nn->laundromat_work);
        if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
                goto skip_grace;
        printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
@@ -9113,10 +9112,7 @@ nfs4_state_shutdown_net(struct net *net)
 
        shrinker_free(nn->nfsd_client_shrinker);
        cancel_work_sync(&nn->nfsd_shrinker_work);
-       spin_lock(&nn->client_lock);
-       nn->client_tracking_active = false;
-       spin_unlock(&nn->client_lock);
-       cancel_delayed_work_sync(&nn->laundromat_work);
+       disable_delayed_work_sync(&nn->laundromat_work);
        locks_end_grace(&nn->nfsd4_manager);
 
        INIT_LIST_HEAD(&reaplist);