Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Feb 2025 02:03:10 GMT
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 29c7551cf797 - stable/14 - nfscl: Re-initialize session seq#s when server shrinks slot table
Message-ID:  <202502250203.51P23AmB063990@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=29c7551cf7970dbe6a869b766a2740864653f3ff

commit 29c7551cf7970dbe6a869b766a2740864653f3ff
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2025-02-11 23:50:57 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2025-02-25 02:01:19 +0000

    nfscl: Re-initialize session seq#s when server shrinks slot table
    
    When a NFSv4.1/4.2 server reduces the size of the slot table
    for a session as indicated by a smaller value for sr_target_highest_slot
    in a Sequence reply, the sequence numbers for the slots no
    longer in use must be re-initialized.  This is needed since the
    slot table may be grown again by the server later.
    
    The RFC did not make the need for the sequence numbers to be
    re-initialized when a shrink/grow of the slot table size happens,
    but this has now been confirmed as correct behaviour.
    
    The patch adds the code that does this re-initialization.
    
    I am not currently aware of a NFSv4.1/4.2 server where the
    session slots fail if this is not done, but there may be such
    a case.
    
    (cherry picked from commit b97a478896e9523245c2041b064121ccb1f70426)
---
 sys/fs/nfs/nfs_commonkrpc.c | 42 ++++++++++++++++++++++++++++++++++--------
 sys/fs/nfs/nfs_commonsubs.c |  2 ++
 2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index e5c658ce76d2..e35172ee2b34 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -123,6 +123,7 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_da
 SYSCTL_INT(_vfs_nfs, OID_AUTO, dsretries, CTLFLAG_RW, &nfs_dsretries, 0,
     "Number of retries for a DS RPC before failure");
 
+static void	nfs_resetslots(struct nfsclsession *);
 static void	nfs_down(struct nfsmount *, struct thread *, const char *,
     int, int);
 static void	nfs_up(struct nfsmount *, struct thread *, const char *,
@@ -670,7 +671,7 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
     struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
     u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *dssep)
 {
-	uint32_t retseq, retval, slotseq, *tl;
+	uint32_t retseq, retval, retval0, slotseq, *tl;
 	int i = 0, j = 0, opcnt, set_sigset = 0, slot;
 	int error = 0, usegssname = 0, secflavour = AUTH_SYS;
 	int freeslot, maxslot, reterr, slotpos, timeo;
@@ -1039,7 +1040,7 @@ tryagain:
 			sep->nfsess_badslots |= (0x1ULL << nd->nd_slotid);
 			mtx_unlock(&sep->nfsess_mtx);
 			/* And free the slot. */
-			nfsv4_freeslot(sep, nd->nd_slotid, false);
+			nfsv4_freeslot(sep, nd->nd_slotid, true);
 		}
 		if (stat == RPC_INTR)
 			error = EINTR;
@@ -1192,15 +1193,22 @@ tryagain:
 					if (retseq != sep->nfsess_slotseq[slot])
 						printf("retseq diff 0x%x\n",
 						    retseq);
-					retval = fxdr_unsigned(uint32_t, *++tl);
+					retval0 = fxdr_unsigned(uint32_t,*tl++);
+					retval = fxdr_unsigned(uint32_t, *tl);
 					if ((retval + 1) < sep->nfsess_foreslots
-					    )
+					    ) {
 						sep->nfsess_foreslots = (retval
 						    + 1);
-					else if ((retval + 1) >
-					    sep->nfsess_foreslots)
-						sep->nfsess_foreslots = (retval
-						    < 64) ? (retval + 1) : 64;
+						nfs_resetslots(sep);
+					} else if ((retval + 1) >
+					    sep->nfsess_foreslots) {
+						if (retval0 > retval)
+							printf("Sess:highest > "
+							    "target_highest\n");
+						sep->nfsess_foreslots =
+						    (retval < NFSV4_SLOTS) ?
+						    (retval + 1) : NFSV4_SLOTS;
+					}
 				}
 				mtx_unlock(&sep->nfsess_mtx);
 
@@ -1463,6 +1471,24 @@ nfsmout:
 	return (error);
 }
 
+/*
+ * Reset slots above nfsess_foreslots that are not busy.
+ */
+static void
+nfs_resetslots(struct nfsclsession *sep)
+{
+	int i;
+	uint64_t bitval;
+
+	bitval = (1 << sep->nfsess_foreslots);
+	for (i = sep->nfsess_foreslots; i < NFSV4_SLOTS; i++) {
+		if ((sep->nfsess_slots & bitval) == 0 &&
+		    (sep->nfsess_badslots & bitval) == 0)
+			sep->nfsess_slotseq[i] = 0;
+		bitval <<= 1;
+	}
+}
+
 /*
  * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
  * wait for all requests to complete. This is used by forced unmounts
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 9e10bba28c90..ffd6d3e50654 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -5051,6 +5051,8 @@ nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
 	mtx_lock(&sep->nfsess_mtx);
 	if (resetseq)
 		sep->nfsess_slotseq[slot]--;
+	else if (slot > sep->nfsess_foreslots)
+		sep->nfsess_slotseq[slot] = 0;
 	if ((bitval & sep->nfsess_slots) == 0)
 		printf("freeing free slot!!\n");
 	sep->nfsess_slots &= ~bitval;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502250203.51P23AmB063990>