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 40ada74ee1
). 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
MFC after: 2 weeks
This commit is contained in:
parent
e0e8d0c8d6
commit
981ef32230
@ -925,10 +925,8 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
|
||||
} 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 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
|
||||
*/
|
||||
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 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
|
||||
* 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 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
|
||||
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 "
|
||||
|
Loading…
Reference in New Issue
Block a user