The branch stable/13 has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4775325dd6615160a3aca19f3a339af63fa0ceb7

commit 4775325dd6615160a3aca19f3a339af63fa0ceb7
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2021-05-19 21:52:56 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2021-06-02 23:54:10 +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 | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 8b5f07b5aa2a..1ed3630ce6e7 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -1996,6 +1996,7 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
        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
@@ -2077,6 +2078,7 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
         * 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);
@@ -2110,6 +2112,7 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
                        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))) {
@@ -2168,6 +2171,21 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
                                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)
@@ -2254,6 +2272,23 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
                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!!
@@ -2261,6 +2296,7 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, 
struct ucred *cred,
                    nfscl_cleandeleg(dp);
                    nfscl_freedeleg(&clp->nfsc_deleg, dp, true);
                } else {
+                   recovered_one = true;
                    LIST_INSERT_HEAD(&extra_open, nop, nfso_list);
                }
            }
_______________________________________________
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"

Reply via email to