Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4beb345b authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields
Browse files

nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it



When we remove the client_mutex protection, we will need to ensure
that it can't be found by other threads while we're destroying it.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 83e452fe
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -1588,12 +1588,23 @@ free_client(struct nfs4_client *clp)
}

/* must be called under the client_lock */
static inline void
static void
unhash_client_locked(struct nfs4_client *clp)
{
	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
	struct nfsd4_session *ses;

	list_del(&clp->cl_lru);
	/* Mark the client as expired! */
	clp->cl_time = 0;
	/* Make it invisible */
	if (!list_empty(&clp->cl_idhash)) {
		list_del_init(&clp->cl_idhash);
		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
		else
			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
	}
	list_del_init(&clp->cl_lru);
	spin_lock(&clp->cl_lock);
	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
		list_del_init(&ses->se_hash);
@@ -1601,7 +1612,17 @@ unhash_client_locked(struct nfs4_client *clp)
}

static void
destroy_client(struct nfs4_client *clp)
unhash_client(struct nfs4_client *clp)
{
	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);

	spin_lock(&nn->client_lock);
	unhash_client_locked(clp);
	spin_unlock(&nn->client_lock);
}

static void
__destroy_client(struct nfs4_client *clp)
{
	struct nfs4_openowner *oo;
	struct nfs4_delegation *dp;
@@ -1634,22 +1655,24 @@ destroy_client(struct nfs4_client *clp)
	nfsd4_shutdown_callback(clp);
	if (clp->cl_cb_conn.cb_xprt)
		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
	list_del(&clp->cl_idhash);
	if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
		rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
	else
		rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
	spin_lock(&nn->client_lock);
	unhash_client_locked(clp);
	WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
	free_client(clp);
	spin_unlock(&nn->client_lock);
}

static void
destroy_client(struct nfs4_client *clp)
{
	unhash_client(clp);
	__destroy_client(clp);
}

static void expire_client(struct nfs4_client *clp)
{
	unhash_client(clp);
	nfsd4_client_record_remove(clp);
	destroy_client(clp);
	__destroy_client(clp);
}

static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)