Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Apr 2010 22:21:23 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r206818 - in head/sys/fs: nfs nfsclient
Message-ID:  <201004182221.o3IMLNFW011567@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004182221.o3IMLNFW011567>