nfs_clstate.c: Fix CB_RECALL handling for NFSv4.1/4.2

Recent testing with a modified NFSv4.1/4.2 client that
sometimes ignored CB_RECALL callbacks, identified a few
problems when handling the unusual case of CB_RECALL not
be performed by the client.
- The csa_cachethis argument to CB_SEQUENCE was being ignored.
- The CB_SEQUENCE operation would reply NFSERR_DELAY
  after the first CB_RECALL attempt, making retries
  ineffective.
- The code could return NFSERR_RESOURCE, which is a
  NFSv4.0 specific error code.

This patch fixes the above three problems.

The patch only affects the NFSv4.1/4.2 client when
delegations are being issued and the client somehow
fails to handle a CB_RECALL callback of a delegation,
which is an unusual case.

MFC after:	2 weeks
This commit is contained in:
Rick Macklem committed 2026-06-27 16:35:20 -07:00
1 parent 4b26ea5471
commit 9e1bbfb88e
1 file changed
+9 -2
+9 -2
View File
@@ -3585,7 +3585,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
mount_t mp;
nfsattrbit_t attrbits, rattrbits;
nfsv4stateid_t stateid;
uint32_t seqid, slotid = 0, highslot, cachethis __unused;
uint32_t seqid, slotid = 0, highslot, cachethis;
uint8_t sessionid[NFSX_V4SESSIONID];
struct mbuf *rep;
struct nfscllayout *lyp;
@@ -3596,6 +3596,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
struct nfsclsession *tsep;
gotseq_ok = 0;
cachethis = 0;
nfsrvd_rephead(nd);
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
taglen = fxdr_unsigned(int, *tl);
@@ -3922,6 +3923,9 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
error = nfsv4_seqsession(seqid, slotid,
highslot, tsep->nfsess_cbslots, &rep,
tsep->nfsess_backslots);
/* For callbacks, do not reply NFSERR_DELAY. */
if (error == NFSERR_DELAY)
error = 0;
}
NFSUNLOCKCLSTATE();
if (error == 0 || error == NFSERR_REPLYFROMCACHE) {
@@ -4065,8 +4069,9 @@ nfsmout:
}
*nd->nd_errp = nfscl_errmap(nd, minorvers);
out:
if (gotseq_ok != 0) {
if (gotseq_ok != 0 && cachethis != 0) {
rep = m_copym(nd->nd_mreq, 0, M_COPYALL, M_WAITOK);
NFSCL_DEBUG(4, "Got reply for cbcache=%p\n", rep);
NFSLOCKCLSTATE();
clp = nfscl_getclntsess(sessionid);
if (clp != NULL) {
@@ -5283,6 +5288,8 @@ nfscl_errmap(struct nfsrv_descript *nd, u_int32_t minorvers)
while (*++errp)
if (*errp == (short)nd->nd_repstat)
return (txdr_unsigned(nd->nd_repstat));
if (minorvers > NFSV4_MINORVERSION && *defaulterrp == NFSERR_RESOURCE)
return (txdr_unsigned(NFSERR_SERVERFAULT));
return (txdr_unsigned(*defaulterrp));
}