Commit 2d3e998a authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: 7d3e26a0 ("NFS: Cancel all existing RPC tasks when shutdown")
Reviewed-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent bf9be373
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -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;
}