Author: rmacklem
Date: Sun Apr 18 22:21:23 2010
New Revision: 206818
URL: http://svn.freebsd.org/changeset/base/206818

Log:
  Avoid extraneous recovery cycles in the experimental NFS client
  when an NFSv4 server reboots, by doing two things.
  1 - Make the function that acquires a stateid for I/O operations
      block until recovery is complete, so that it doesn't acquire
      out of date stateids.
  2 - Only allow a recovery once every 1/2 of a lease duration, since
      the NFSv4 server must provide a recovery grace period of at
      least a lease duration. This should avoid recoveries caused
      by an out of date stateid that was acquired for an I/O op.
      just before a recovery cycle started.
  
  MFC after:    1 week

Modified:
  head/sys/fs/nfs/nfsclstate.h
  head/sys/fs/nfsclient/nfs_clstate.c

Modified: head/sys/fs/nfs/nfsclstate.h
==============================================================================
--- head/sys/fs/nfs/nfsclstate.h        Sun Apr 18 22:13:45 2010        
(r206817)
+++ head/sys/fs/nfs/nfsclstate.h        Sun Apr 18 22:21:23 2010        
(r206818)
@@ -74,6 +74,7 @@ struct nfsclclient {
 #define        NFSCLFLAGS_EXPIREIT     0x0040
 #define        NFSCLFLAGS_FIRSTDELEG   0x0080
 #define        NFSCLFLAGS_GOTDELEG     0x0100
+#define        NFSCLFLAGS_RECVRINPROG  0x0200
 
 struct nfsclowner {
        LIST_ENTRY(nfsclowner)  nfsow_list;

Modified: head/sys/fs/nfsclient/nfs_clstate.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clstate.c Sun Apr 18 22:13:45 2010        
(r206817)
+++ head/sys/fs/nfsclient/nfs_clstate.c Sun Apr 18 22:21:23 2010        
(r206818)
@@ -481,6 +481,13 @@ nfscl_getstateid(vnode_t vp, u_int8_t *n
        }
 
        /*
+        * Wait for recovery to complete.
+        */
+       while ((clp->nfsc_flags & NFSCLFLAGS_RECVRINPROG))
+               (void) nfsmsleep(&clp->nfsc_flags, NFSCLSTATEMUTEXPTR,
+                   PZERO, "nfsrecvr", NULL);
+
+       /*
         * First, look for a delegation.
         */
        LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) {
@@ -1778,6 +1785,7 @@ nfscl_recover(struct nfsclclient *clp, s
         * block when trying to use state.
         */
        NFSLOCKCLSTATE();
+       clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
        do {
                igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
                    NFSCLSTATEMUTEXPTR);
@@ -1794,9 +1802,10 @@ nfscl_recover(struct nfsclclient *clp, s
             error == NFSERR_STALEDONTRECOVER) && --trycnt > 0);
        if (error) {
                nfscl_cleanclient(clp);
-               clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
-                   NFSCLFLAGS_RECOVER);
                NFSLOCKCLSTATE();
+               clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
+                   NFSCLFLAGS_RECOVER | NFSCLFLAGS_RECVRINPROG);
+               wakeup(&clp->nfsc_flags);
                nfsv4_unlock(&clp->nfsc_lock, 0);
                NFSUNLOCKCLSTATE();
                return;
@@ -2057,6 +2066,8 @@ nfscl_recover(struct nfsclclient *clp, s
        }
 
        NFSLOCKCLSTATE();
+       clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG;
+       wakeup(&clp->nfsc_flags);
        nfsv4_unlock(&clp->nfsc_lock, 0);
        NFSUNLOCKCLSTATE();
        NFSFREECRED(tcred);
@@ -2316,6 +2327,7 @@ nfscl_renewthread(struct nfsclclient *cl
        struct ucred *cred;
        u_int32_t clidrev;
        int error, cbpathdown, islept, igotlock, ret, clearok;
+       uint32_t recover_done_time = 0;
 
        cred = newnfs_getcred();
        NFSLOCKCLSTATE();
@@ -2324,8 +2336,21 @@ nfscl_renewthread(struct nfsclclient *cl
        for(;;) {
                newnfs_setroot(cred);
                cbpathdown = 0;
-               if (clp->nfsc_flags & NFSCLFLAGS_RECOVER)
-                       nfscl_recover(clp, cred, p);
+               if (clp->nfsc_flags & NFSCLFLAGS_RECOVER) {
+                       /*
+                        * Only allow one recover within 1/2 of the lease
+                        * duration (nfsc_renew).
+                        */
+                       if (recover_done_time < NFSD_MONOSEC) {
+                               recover_done_time = NFSD_MONOSEC +
+                                   clp->nfsc_renew;
+                               nfscl_recover(clp, cred, p);
+                       } else {
+                               NFSLOCKCLSTATE();
+                               clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
+                               NFSUNLOCKCLSTATE();
+                       }
+               }
                if (clp->nfsc_expire <= NFSD_MONOSEC &&
                    (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) {
                        clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to