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

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
...@@ -1588,12 +1588,23 @@ free_client(struct nfs4_client *clp) ...@@ -1588,12 +1588,23 @@ free_client(struct nfs4_client *clp)
} }
/* must be called under the client_lock */ /* must be called under the client_lock */
static inline void static void
unhash_client_locked(struct nfs4_client *clp) unhash_client_locked(struct nfs4_client *clp)
{ {
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
struct nfsd4_session *ses; 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); spin_lock(&clp->cl_lock);
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
list_del_init(&ses->se_hash); list_del_init(&ses->se_hash);
...@@ -1601,7 +1612,17 @@ unhash_client_locked(struct nfs4_client *clp) ...@@ -1601,7 +1612,17 @@ unhash_client_locked(struct nfs4_client *clp)
} }
static void 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_openowner *oo;
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
...@@ -1634,22 +1655,24 @@ destroy_client(struct nfs4_client *clp) ...@@ -1634,22 +1655,24 @@ destroy_client(struct nfs4_client *clp)
nfsd4_shutdown_callback(clp); nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt) if (clp->cl_cb_conn.cb_xprt)
svc_xprt_put(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); spin_lock(&nn->client_lock);
unhash_client_locked(clp);
WARN_ON_ONCE(atomic_read(&clp->cl_refcount)); WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
free_client(clp); free_client(clp);
spin_unlock(&nn->client_lock); 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) static void expire_client(struct nfs4_client *clp)
{ {
unhash_client(clp);
nfsd4_client_record_remove(clp); nfsd4_client_record_remove(clp);
destroy_client(clp); __destroy_client(clp);
} }
static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment