--- sys/fs/nfs/nfs_commonsubs.c.slot 2022-05-20 16:07:41.772273000 -0700 +++ sys/fs/nfs/nfs_commonsubs.c 2022-05-21 05:19:50.789925000 -0700 @@ -81,6 +81,7 @@ NFSNAMEIDMUTEX; NFSSOCKMUTEX; extern int nfsrv_lughashsize; extern struct mtx nfsrv_dslock_mtx; +extern struct mtx nfs_clstate_mutex; extern volatile int nfsrv_devidcnt; extern int nfscl_debuglevel; extern struct nfsdevicehead nfsrv_devidhead; @@ -4823,31 +4824,73 @@ nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsc { int i, maxslot, slotpos; uint64_t bitval; + bool fnd_okslot; /* Find an unused slot. */ slotpos = -1; maxslot = -1; mtx_lock(&sep->nfsess_mtx); +if (sep->nfsess_badslots != 0) printf("badslots=0x%lx\n", sep->nfsess_badslots); do { - if (nmp != NULL && sep->nfsess_defunct != 0) { - /* Just return the bad session. */ - bcopy(sep->nfsess_sessionid, sessionid, - NFSX_V4SESSIONID); - mtx_unlock(&sep->nfsess_mtx); - return (NFSERR_BADSESSION); + fnd_okslot = true; + if (nmp != NULL) { + KASSERT(TAILQ_FIRST(&nmp->nm_sess) != NULL, + ("nfsv4_sequencelookup: no mds sess")); + if (sep->nfsess_defunct != 0) { + /* Just return the bad session. */ + bcopy(sep->nfsess_sessionid, sessionid, + NFSX_V4SESSIONID); + mtx_unlock(&sep->nfsess_mtx); + return (NFSERR_BADSESSION); + } + + /* Only check for bad slots on the MDS session. */ + if (NFSMNT_MDSSESSION(nmp) == sep) + fnd_okslot = false; } bitval = 1; for (i = 0; i < sep->nfsess_foreslots; i++) { - if ((bitval & sep->nfsess_slots) == 0) { - slotpos = i; - sep->nfsess_slots |= bitval; - sep->nfsess_slotseq[i]++; - *slotseqp = sep->nfsess_slotseq[i]; - break; + if ((bitval & sep->nfsess_badslots) == 0) { + fnd_okslot = true; + if ((bitval & sep->nfsess_slots) == 0) { + slotpos = i; + sep->nfsess_slots |= bitval; + sep->nfsess_slotseq[i]++; + *slotseqp = sep->nfsess_slotseq[i]; + break; + } } bitval <<= 1; } if (slotpos == -1) { + if (!fnd_okslot) { + /* + * All slots are broken, so mark the session + * defunct. + */ + bcopy(sep->nfsess_sessionid, sessionid, + NFSX_V4SESSIONID); + sep->nfsess_defunct = 1; +printf("all badslots\n"); + mtx_unlock(&sep->nfsess_mtx); + NFSCL_DEBUG(1, "Marked defunct\n"); + + /* + * If this is the current session, + * initiate recovery. + */ + NFSLOCKCLSTATE(); + NFSLOCKMNT(nmp); + if (nmp->nm_clp != NULL && + NFSMNT_MDSSESSION(nmp) == sep) { + nmp->nm_clp->nfsc_flags |= + NFSCLFLAGS_RECOVER; + wakeup(nmp->nm_clp); + } + NFSUNLOCKCLSTATE(); + NFSUNLOCKMNT(nmp); + return (NFSERR_BADSESSION); + } /* * If a forced dismount is in progress, just return. * This RPC attempt will fail when it calls --- sys/fs/nfs/nfs_commonkrpc.c.slot 2022-05-20 16:15:42.665994000 -0700 +++ sys/fs/nfs/nfs_commonkrpc.c 2022-05-21 17:06:45.283183000 -0700 @@ -606,6 +606,7 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmo uint8_t sessionid[NFSX_V4SESSIONID]; bool nextconn_set; struct timespec trylater_delay, ts, waituntil; + struct nfsclds *dsp; /* Initially 1msec. */ trylater_delay.tv_sec = 0; @@ -951,6 +952,7 @@ tryagain: */ mtx_lock(&sep->nfsess_mtx); sep->nfsess_slotseq[nd->nd_slotid] += 10; + sep->nfsess_badslots |= (1 << nd->nd_slotid); mtx_unlock(&sep->nfsess_mtx); /* And free the slot. */ nfsv4_freeslot(sep, nd->nd_slotid, false); @@ -1093,16 +1095,28 @@ tryagain: NFSCL_DEBUG(1, "Got badsession\n"); NFSLOCKCLSTATE(); NFSLOCKMNT(nmp); - sep = NFSMNT_MDSSESSION(nmp); - if (bcmp(sep->nfsess_sessionid, nd->nd_sequence, - NFSX_V4SESSIONID) == 0) { - /* Initiate recovery. */ - sep->nfsess_defunct = 1; - NFSCL_DEBUG(1, "Marked defunct\n"); - if (nmp->nm_clp != NULL) { - nmp->nm_clp->nfsc_flags |= - NFSCLFLAGS_RECOVER; - wakeup(nmp->nm_clp); + TAILQ_FOREACH(dsp, &nmp->nm_sess, + nfsclds_list) { + sep = &dsp->nfsclds_sess; + if ((dsp->nfsclds_flags & + NFSCLDS_DSSESS) == 0 && + bcmp(sep->nfsess_sessionid, + nd->nd_sequence, + NFSX_V4SESSIONID) == 0) { + /* Initiate recovery. */ + sep->nfsess_defunct = 1; + NFSCL_DEBUG(1, + "Marked defunct\n"); +printf("newnfs_req: sess defunct\n"); + if (nmp->nm_clp != NULL && + NFSMNT_MDSSESSION(nmp) == + sep) { +printf("newnfs_req: init recvr\n"); + nmp->nm_clp->nfsc_flags |= + NFSCLFLAGS_RECOVER; + wakeup(nmp->nm_clp); + } + break; } } NFSUNLOCKCLSTATE(); --- sys/fs/nfs/nfsclstate.h.slot 2022-05-20 16:16:48.454756000 -0700 +++ sys/fs/nfs/nfsclstate.h 2022-05-21 17:03:13.519408000 -0700 @@ -67,6 +67,7 @@ struct nfsclsession { SVCXPRT *nfsess_xprt; /* For backchannel callback */ uint32_t nfsess_slotseq[64]; /* Max for 64bit nm_slots */ uint64_t nfsess_slots; + uint64_t nfsess_badslots; /* Slots that are broken */ uint32_t nfsess_sequenceid; uint32_t nfsess_maxcache; /* Max size for cached reply. */ uint32_t nfsess_maxreq; /* Max request size. */ @@ -103,6 +104,7 @@ struct nfsclds { #define NFSCLDS_CLOSED 0x0008 #define NFSCLDS_SAMECONN 0x0010 #define NFSCLDS_MINORV2 0x0020 +#define NFSCLDS_DSSESS 0x0040 struct nfsclclient { LIST_ENTRY(nfsclclient) nfsc_list; --- sys/fs/nfsclient/nfs_clrpcops.c.slot 2022-05-20 16:18:41.641440000 -0700 +++ sys/fs/nfsclient/nfs_clrpcops.c 2022-05-21 17:02:31.326822000 -0700 @@ -6001,6 +6001,8 @@ nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in firsttry++ == 0); if (error != 0) newnfs_disconnect(NULL, nrp); + else + dsp->nfsclds_flags |= NFSCLDS_DSSESS; } else { dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); @@ -6107,6 +6109,7 @@ nfscl_initsessionslots(struct nfsclsession *sep) for (i = 0; i < 64; i++) sep->nfsess_slotseq[i] = 0; sep->nfsess_slots = 0; + sep->nfsess_badslots = 0; } /*