git: f5fb5e07df5b - stable/13 - nfscl: Enable detection of bad session slots
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 28 Jul 2022 20:15:58 UTC
The branch stable/13 has been updated by rmacklem:
URL: https://cgit.FreeBSD.org/src/commit/?id=f5fb5e07df5bd7a6df170474a3df724ee3538785
commit f5fb5e07df5bd7a6df170474a3df724ee3538785
Author: Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2022-07-10 20:33:19 +0000
Commit: Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2022-07-28 20:11:07 +0000
nfscl: Enable detection of bad session slots
To deal with broken session slots caused by the use of the
"soft" and/or "intr" mount options, nfsv4_sequencelookup()
has been modified to track the potentially broken session
slots (commit 40ada74ee1da). Then, when all session slots
are potentially broken, nfsv4_sequencelookup() does a
DeleteSession operation, so that the NFSv4.1/4.2 server will
reply NFSERR_BADSESSION to uses of the session.
The client will then recover by doing a CreateSession to
acquire a new session.
This patch adds the code that marks potentially bad
slots, so that the above semantics become functional.
It has been successfully tested against a FreeBSD
NFSv4.1/4.2 server, but does not work against a Linux 5.15
NFSv4.1/4.2 server. (The Linux 5.15 server creates
a new session with the same sessionid as the destroyed
one and, as such, keeps returning NFSERR_BADSESSION.
I believe this is a bug in the Linux server.)
However, this should not cause a regression and will
make "intr" mounts fairly usable against the NFSv4.1/4.2
servers where it works.
PR: 260011
(cherry picked from commit 981ef32230b2fe46969c90b53864bdca4f1c3ae5)
---
sys/fs/nfs/nfs_commonkrpc.c | 53 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 44 insertions(+), 9 deletions(-)
diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index 20b12767d29d..150d92414e7a 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -925,10 +925,8 @@ tryagain:
} else if (stat == RPC_PROGVERSMISMATCH) {
NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
error = EPROTONOSUPPORT;
- } else if (stat == RPC_INTR) {
- error = EINTR;
} else if (stat == RPC_CANTSEND || stat == RPC_CANTRECV ||
- stat == RPC_SYSTEMERROR) {
+ stat == RPC_SYSTEMERROR || stat == RPC_INTR) {
/* Check for a session slot that needs to be free'd. */
if ((nd->nd_flag & (ND_NFSV41 | ND_HASSLOTID)) ==
(ND_NFSV41 | ND_HASSLOTID) && nmp != NULL &&
@@ -951,12 +949,17 @@ tryagain:
*/
mtx_lock(&sep->nfsess_mtx);
sep->nfsess_slotseq[nd->nd_slotid] += 10;
+ sep->nfsess_badslots |= (0x1ULL << nd->nd_slotid);
mtx_unlock(&sep->nfsess_mtx);
/* And free the slot. */
nfsv4_freeslot(sep, nd->nd_slotid, false);
}
- NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
- error = ENXIO;
+ if (stat == RPC_INTR)
+ error = EINTR;
+ else {
+ NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
+ error = ENXIO;
+ }
} else {
NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
error = EACCES;
@@ -1019,8 +1022,16 @@ tryagain:
* If the first op is Sequence, free up the slot.
*/
if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) ||
- (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0))
+ (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0)) {
NFSCL_DEBUG(1, "failed seq=%d\n", j);
+ if (sep != NULL && i == NFSV4OP_SEQUENCE &&
+ j == NFSERR_SEQMISORDERED) {
+ mtx_lock(&sep->nfsess_mtx);
+ sep->nfsess_badslots |=
+ (0x1ULL << nd->nd_slotid);
+ mtx_unlock(&sep->nfsess_mtx);
+ }
+ }
if (((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) ||
(clp != NULL && i == NFSV4OP_CBSEQUENCE &&
j == 0)) && sep != NULL) {
@@ -1039,11 +1050,35 @@ tryagain:
retseq = fxdr_unsigned(uint32_t, *tl++);
slot = fxdr_unsigned(int, *tl++);
if ((nd->nd_flag & ND_HASSLOTID) != 0) {
- if (slot != nd->nd_slotid) {
+ if (slot >= NFSV4_SLOTS ||
+ (i == NFSV4OP_CBSEQUENCE &&
+ slot >= NFSV4_CBSLOTS)) {
printf("newnfs_request:"
- " Wrong session "
- "slot=%d\n", slot);
+ " Bogus slot\n");
slot = nd->nd_slotid;
+ } else if (slot !=
+ nd->nd_slotid) {
+ printf("newnfs_request:"
+ " Wrong session "
+ "srvslot=%d "
+ "slot=%d\n", slot,
+ nd->nd_slotid);
+ if (i == NFSV4OP_SEQUENCE) {
+ /*
+ * Mark both slots as
+ * bad, because we do
+ * not know if the
+ * server has advanced
+ * the sequence# for
+ * either of them.
+ */
+ sep->nfsess_badslots |=
+ (0x1ULL << slot);
+ sep->nfsess_badslots |=
+ (0x1ULL <<
+ nd->nd_slotid);
+ }
+ slot = nd->nd_slotid;
}
} else if (slot != 0) {
printf("newnfs_request: Bad "