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

Commit 26c0c75e authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

nfsd4: fix unlikely race in session replay case



In the replay case, the

	renew_client(session->se_client);

happens after we've droppped the sessionid_lock, and without holding a
reference on the session; so there's nothing preventing the session
being freed before we get here.

Thanks to Benny Halevy for catching a bug in an earlier version of this
patch.

Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Acked-by: default avatarBenny Halevy <bhalevy@panasas.com>
parent e0c82336
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1027,6 +1027,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
	resp->rqstp = rqstp;
	resp->cstate.minorversion = args->minorversion;
	resp->cstate.replay_owner = NULL;
	resp->cstate.session = NULL;
	fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
	fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
	/* Use the deferral mechanism only for NFSv4.0 compounds */
+3 −4
Original line number Diff line number Diff line
@@ -1443,11 +1443,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
	cstate->slot = slot;
	cstate->session = session;

	/* Hold a session reference until done processing the compound:
	 * nfsd4_put_session called only if the cstate slot is set.
	 */
	nfsd4_get_session(session);
out:
	/* Hold a session reference until done processing the compound. */
	if (cstate->session)
		nfsd4_get_session(cstate->session);
	spin_unlock(&sessionid_lock);
	/* Renew the clientid on success and on replay */
	if (cstate->session) {
+6 −4
Original line number Diff line number Diff line
@@ -3306,10 +3306,12 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
		iov = &rqstp->rq_res.head[0];
	iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
	BUG_ON(iov->iov_len > PAGE_SIZE);
	if (nfsd4_has_session(cs) && cs->status != nfserr_replay_cache) {
	if (nfsd4_has_session(cs)) {
		if (cs->status != nfserr_replay_cache) {
			nfsd4_store_cache_entry(resp);
			dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
			resp->cstate.slot->sl_inuse = false;
		}
		nfsd4_put_session(resp->cstate.session);
	}
	return 1;