]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2025 12:37:35 +0000 (14:37 +0200)
[ Upstream commit 2d3e998a0bc7fe26a724f87a8ce217848040520e ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/sysfs.c

index 7b59a40d40c061a41b0fbde91aa006314f02c1fb..784f7c1d003bfcb56ea058587d6598b1567d26a9 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;
 }