NFS: Shut down the nfs_client only after all the superblocks

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: 7d3e26a054 ("NFS: Cancel all existing RPC tasks when shutdown")
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Trond Myklebust 2025-03-25 17:58:50 -04:00
parent bf9be373b8
commit 2d3e998a0b

View 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;
}