mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
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 commite4469c6cc6
("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:e4469c6cc6
("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>
This commit is contained in:
parent
6978bd6a91
commit
99dc2ef039
@ -3831,15 +3831,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
else
|
||||
cs_slot = &unconf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
if (status) {
|
||||
if (status == nfserr_replay_cache) {
|
||||
status = nfsd4_replay_create_session(cr_ses, cs_slot);
|
||||
goto out_free_conn;
|
||||
}
|
||||
switch (status) {
|
||||
case nfs_ok:
|
||||
cs_slot->sl_seqid++;
|
||||
cr_ses->seqid = cs_slot->sl_seqid;
|
||||
break;
|
||||
case nfserr_replay_cache:
|
||||
status = nfsd4_replay_create_session(cr_ses, cs_slot);
|
||||
fallthrough;
|
||||
case nfserr_jukebox:
|
||||
/* The server MUST NOT cache NFS4ERR_DELAY */
|
||||
goto out_free_conn;
|
||||
default:
|
||||
goto out_cache_error;
|
||||
}
|
||||
cs_slot->sl_seqid++;
|
||||
cr_ses->seqid = cs_slot->sl_seqid;
|
||||
|
||||
/* RFC 8881 Section 18.36.4 Phase 3: Client ID confirmation. */
|
||||
if (conf) {
|
||||
@ -3859,10 +3864,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
|
||||
if (old) {
|
||||
status = mark_client_expired_locked(old);
|
||||
if (status) {
|
||||
old = NULL;
|
||||
goto out_cache_error;
|
||||
}
|
||||
if (status)
|
||||
goto out_expired_error;
|
||||
trace_nfsd_clid_replaced(&old->cl_clientid);
|
||||
}
|
||||
move_to_confirmed(unconf);
|
||||
@ -3894,6 +3897,17 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
expire_client(old);
|
||||
return status;
|
||||
|
||||
out_expired_error:
|
||||
old = NULL;
|
||||
/*
|
||||
* Revert the slot seq_nr change so the server will process
|
||||
* the client's resend instead of returning a cached response.
|
||||
*/
|
||||
if (status == nfserr_jukebox) {
|
||||
cs_slot->sl_seqid--;
|
||||
cr_ses->seqid = cs_slot->sl_seqid;
|
||||
goto out_free_conn;
|
||||
}
|
||||
out_cache_error:
|
||||
nfsd4_cache_create_session(cr_ses, cs_slot, status);
|
||||
out_free_conn:
|
||||
|
Loading…
Reference in New Issue
Block a user