Skip to content

Commit 99dc2ef

Browse files
committed
NFSD: CREATE_SESSION must never cache NFS4ERR_DELAY replies
There are one or two cases where CREATE_SESSION returns NFS4ERR_DELAY in order to force the client to wait a bit and try CREATE_SESSION again. However, after commit e4469c6 ("NFSD: Fix the NFSv4.1 CREATE_SESSION operation"), NFSD caches that response in the CREATE_SESSION slot. Thus, when the client resends the CREATE_SESSION, the server always returns the cached NFS4ERR_DELAY response rather than actually executing the request and properly recording its outcome. This blocks the client from making further progress. RFC 8881 Section 15.1.1.3 says: > If NFS4ERR_DELAY is returned on an operation other than SEQUENCE > that validly appears as the first operation of a request ... [t]he > request can be retried in full without modification. In this case > as well, the replier MUST avoid returning a response containing > NFS4ERR_DELAY as the response to an initial operation of a request > solely on the basis of its presence in the reply cache. Neither the original NFSD code nor the discussion in section 18.36.4 refer explicitly to this important requirement, so I missed it. Note also that not only must the server not cache NFS4ERR_DELAY, but it has to not advance the CREATE_SESSION slot sequence number so that it can properly recognize and accept the client's retry. Reported-by: Dai Ngo <dai.ngo@oracle.com> Fixes: e4469c6 ("NFSD: Fix the NFSv4.1 CREATE_SESSION operation") Tested-by: Dai Ngo <dai.ngo@oracle.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 6978bd6 commit 99dc2ef

File tree

1 file changed

+25
-11
lines changed

1 file changed

+25
-11
lines changed

fs/nfsd/nfs4state.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,15 +3831,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,
38313831
else
38323832
cs_slot = &unconf->cl_cs_slot;
38333833
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
3834-
if (status) {
3835-
if (status == nfserr_replay_cache) {
3836-
status = nfsd4_replay_create_session(cr_ses, cs_slot);
3837-
goto out_free_conn;
3838-
}
3834+
switch (status) {
3835+
case nfs_ok:
3836+
cs_slot->sl_seqid++;
3837+
cr_ses->seqid = cs_slot->sl_seqid;
3838+
break;
3839+
case nfserr_replay_cache:
3840+
status = nfsd4_replay_create_session(cr_ses, cs_slot);
3841+
fallthrough;
3842+
case nfserr_jukebox:
3843+
/* The server MUST NOT cache NFS4ERR_DELAY */
3844+
goto out_free_conn;
3845+
default:
38393846
goto out_cache_error;
38403847
}
3841-
cs_slot->sl_seqid++;
3842-
cr_ses->seqid = cs_slot->sl_seqid;
38433848

38443849
/* RFC 8881 Section 18.36.4 Phase 3: Client ID confirmation. */
38453850
if (conf) {
@@ -3859,10 +3864,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
38593864
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
38603865
if (old) {
38613866
status = mark_client_expired_locked(old);
3862-
if (status) {
3863-
old = NULL;
3864-
goto out_cache_error;
3865-
}
3867+
if (status)
3868+
goto out_expired_error;
38663869
trace_nfsd_clid_replaced(&old->cl_clientid);
38673870
}
38683871
move_to_confirmed(unconf);
@@ -3894,6 +3897,17 @@ nfsd4_create_session(struct svc_rqst *rqstp,
38943897
expire_client(old);
38953898
return status;
38963899

3900+
out_expired_error:
3901+
old = NULL;
3902+
/*
3903+
* Revert the slot seq_nr change so the server will process
3904+
* the client's resend instead of returning a cached response.
3905+
*/
3906+
if (status == nfserr_jukebox) {
3907+
cs_slot->sl_seqid--;
3908+
cr_ses->seqid = cs_slot->sl_seqid;
3909+
goto out_free_conn;
3910+
}
38973911
out_cache_error:
38983912
nfsd4_cache_create_session(cr_ses, cs_slot, status);
38993913
out_free_conn:

0 commit comments

Comments
 (0)