svn commit: r206818 - in head/sys/fs: nfs nfsclient
Rick Macklem
rmacklem at FreeBSD.org
Sun Apr 18 22:21:23 UTC 2010
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;
More information about the svn-src-all
mailing list