Commit abcdff09 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: fix destroy_session race

destroy_session uses the session and client without continuously holding
any reference or locks.

Put the whole thing under the state lock for now.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent bfa85e83
...@@ -1926,41 +1926,35 @@ nfsd4_destroy_session(struct svc_rqst *r, ...@@ -1926,41 +1926,35 @@ nfsd4_destroy_session(struct svc_rqst *r,
struct nfsd4_destroy_session *sessionid) struct nfsd4_destroy_session *sessionid)
{ {
struct nfsd4_session *ses; struct nfsd4_session *ses;
__be32 status = nfserr_badsession; __be32 status;
struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
/* Notes: nfs4_lock_state();
* - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid status = nfserr_not_only_op;
* - Should we return nfserr_back_chan_busy if waiting for
* callbacks on to-be-destroyed session?
* - Do we need to clear any callback info from previous session?
*/
if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
if (!nfsd4_last_compound_op(r)) if (!nfsd4_last_compound_op(r))
return nfserr_not_only_op; goto out;
} }
dump_sessionid(__func__, &sessionid->sessionid); dump_sessionid(__func__, &sessionid->sessionid);
spin_lock(&nn->client_lock); spin_lock(&nn->client_lock);
ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
if (!ses) { status = nfserr_badsession;
spin_unlock(&nn->client_lock); if (!ses)
goto out; goto out_client_lock;
}
unhash_session(ses); unhash_session(ses);
spin_unlock(&nn->client_lock); spin_unlock(&nn->client_lock);
nfs4_lock_state();
nfsd4_probe_callback_sync(ses->se_client); nfsd4_probe_callback_sync(ses->se_client);
nfs4_unlock_state();
spin_lock(&nn->client_lock); spin_lock(&nn->client_lock);
nfsd4_del_conns(ses); nfsd4_del_conns(ses);
nfsd4_put_session_locked(ses); nfsd4_put_session_locked(ses);
spin_unlock(&nn->client_lock);
status = nfs_ok; status = nfs_ok;
out_client_lock:
spin_unlock(&nn->client_lock);
out: out:
nfs4_unlock_state();
return status; return status;
} }
......
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