NFS: Shut down the nfs_client only after all the superblocks
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 25 Mar 2025 21:58:50 +0000 (17:58 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 26 Mar 2025 16:17:48 +0000 (12:17 -0400)
The nfs_client manages state for all the superblocks in the
"cl_superblocks" list, so it must not be shut down until all of them are
gone.

Fixes: 7d3e26a054c8 ("NFS: Cancel all existing RPC tasks when shutdown")
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/sysfs.c

index b30401b2c939a1dac676dde12453614a6758fb5e..37cb2b776435925e4fa9d4a5dde658431a545835 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/rcupdate.h>
 #include <linux/lockd/lockd.h>
 
+#include "internal.h"
 #include "nfs4_fs.h"
 #include "netns.h"
 #include "sysfs.h"
@@ -228,6 +229,25 @@ static void shutdown_client(struct rpc_clnt *clnt)
        rpc_cancel_tasks(clnt, -EIO, shutdown_match_client, NULL);
 }
 
+/*
+ * Shut down the nfs_client only once all the superblocks
+ * have been shut down.
+ */
+static void shutdown_nfs_client(struct nfs_client *clp)
+{
+       struct nfs_server *server;
+       rcu_read_lock();
+       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
+               if (!(server->flags & NFS_MOUNT_SHUTDOWN)) {
+                       rcu_read_unlock();
+                       return;
+               }
+       }
+       rcu_read_unlock();
+       nfs_mark_client_ready(clp, -EIO);
+       shutdown_client(clp->cl_rpcclient);
+}
+
 static ssize_t
 shutdown_show(struct kobject *kobj, struct kobj_attribute *attr,
                                char *buf)
@@ -259,7 +279,6 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
 
        server->flags |= NFS_MOUNT_SHUTDOWN;
        shutdown_client(server->client);
-       shutdown_client(server->nfs_client->cl_rpcclient);
 
        if (!IS_ERR(server->client_acl))
                shutdown_client(server->client_acl);
@@ -267,6 +286,7 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
        if (server->nlm_host)
                shutdown_client(server->nlm_host->h_rpcclnt);
 out:
+       shutdown_nfs_client(server->nfs_client);
        return count;
 }