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,
struct nfsd4_destroy_session *sessionid)
{
struct nfsd4_session *ses;
__be32 status = nfserr_badsession;
__be32 status;
struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
/* Notes:
* - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
* - 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?
*/
nfs4_lock_state();
status = nfserr_not_only_op;
if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
if (!nfsd4_last_compound_op(r))
return nfserr_not_only_op;
goto out;
}
dump_sessionid(__func__, &sessionid->sessionid);
spin_lock(&nn->client_lock);
ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
if (!ses) {
spin_unlock(&nn->client_lock);
goto out;
}
status = nfserr_badsession;
if (!ses)
goto out_client_lock;
unhash_session(ses);
spin_unlock(&nn->client_lock);
nfs4_lock_state();
nfsd4_probe_callback_sync(ses->se_client);
nfs4_unlock_state();
spin_lock(&nn->client_lock);
nfsd4_del_conns(ses);
nfsd4_put_session_locked(ses);
spin_unlock(&nn->client_lock);
status = nfs_ok;
out_client_lock:
spin_unlock(&nn->client_lock);
out:
nfs4_unlock_state();
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