The branch stable/12 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=8513b4f15362161c38c18a4262997468951d3ea0
commit 8513b4f15362161c38c18a4262997468951d3ea0 Author: Rick Macklem <rmack...@freebsd.org> AuthorDate: 2021-05-19 21:52:56 +0000 Commit: Rick Macklem <rmack...@freebsd.org> CommitDate: 2021-06-04 03:19:04 +0000 nfscl: Fix NFSv4.1/4.2 mount recovery from an expired lease The most difficult NFSv4 client recovery case happens when the lease has expired on the server. For NFSv4.0, the client will receive a NFSERR_EXPIRED reply from the server to indicate this has happened. For NFSv4.1/4.2, most RPCs have a Sequence operation and, as such, the client will receive a NFSERR_BADSESSION reply when the lease has expired for these RPCs. The client will then call nfscl_recover() to handle the NFSERR_BADSESSION reply. However, for the expired lease case, the first reclaim Open will fail with NFSERR_NOGRACE. This patch recognizes this case and calls nfscl_expireclient() to handle the recovery from an expired lease. This patch only affects NFSv4.1/4.2 mounts when the lease expires on the server, due to a network partitioning that exceeds the lease duration or similar. (cherry picked from commit c28cb257ddfe3339756f6fd659fa4a2efa4de2cb) --- sys/fs/nfsclient/nfs_clstate.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index e705af31185b..9965b7ca7e4f 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -1977,6 +1977,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) u_int32_t delegtype = NFSV4OPEN_DELEGATEWRITE, mode; int i, igotlock = 0, error, trycnt, firstlock; struct nfscllayout *lyp, *nlyp; + bool recovered_one; /* * First, lock the client structure, so everyone else will @@ -2050,6 +2051,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) * Now traverse the state lists, doing Open and Lock Reclaims. */ tcred = newnfs_getcred(); + recovered_one = false; owp = LIST_FIRST(&clp->nfsc_owner); while (owp != NULL) { nowp = LIST_NEXT(owp, nfsow_list); @@ -2083,6 +2085,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) op->nfso_mode, op, NULL, 0, &ndp, 1, delegtype, tcred, p); if (!error) { + recovered_one = true; /* Handle any replied delegation */ if (ndp != NULL && ((ndp->nfsdl_flags & NFSCLDL_WRITE) || NFSMNT_RDONLY(nmp->nm_mountp))) { @@ -2141,6 +2144,21 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) nfscl_freelockowner(lp, 0); lp = nlp; } + } else if (error == NFSERR_NOGRACE && !recovered_one && + NFSHASNFSV4N(nmp)) { + /* + * For NFSv4.1/4.2, the NFSERR_EXPIRED case will + * actually end up here, since the client will do + * a recovery for NFSERR_BADSESSION, but will get + * an NFSERR_NOGRACE reply for the first "reclaim" + * attempt. + * So, call nfscl_expireclient() to recover the + * opens as best we can and then do a reclaim + * complete and return. + */ + nfsrpc_reclaimcomplete(nmp, cred, p); + nfscl_expireclient(clp, nmp, tcred, p); + goto out; } } if (error != 0 && error != NFSERR_BADSESSION) @@ -2227,6 +2245,23 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) if (error) { if (nop != NULL) free(nop, M_NFSCLOPEN); + if (error == NFSERR_NOGRACE && !recovered_one && + NFSHASNFSV4N(nmp)) { + /* + * For NFSv4.1/4.2, the NFSERR_EXPIRED case will + * actually end up here, since the client will do + * a recovery for NFSERR_BADSESSION, but will get + * an NFSERR_NOGRACE reply for the first "reclaim" + * attempt. + * So, call nfscl_expireclient() to recover the + * opens as best we can and then do a reclaim + * complete and return. + */ + nfsrpc_reclaimcomplete(nmp, cred, p); + nfscl_expireclient(clp, nmp, tcred, p); + free(nowp, M_NFSCLOWNER); + goto out; + } /* * Couldn't reclaim it, so throw the state * away. Ouch!! @@ -2234,6 +2269,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) nfscl_cleandeleg(dp); nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } else { + recovered_one = true; LIST_INSERT_HEAD(&extra_open, nop, nfso_list); } } @@ -2271,6 +2307,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) if (NFSHASNFSV4N(nmp)) (void)nfsrpc_reclaimcomplete(nmp, cred, p); +out: NFSLOCKCLSTATE(); clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG; wakeup(&clp->nfsc_flags); _______________________________________________ dev-commits-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"