Author: jhb
Date: Wed Jan 25 20:05:58 2012
New Revision: 230547
URL: http://svn.freebsd.org/changeset/base/230547

Log:
  Add a timeout on positive name cache entries in the NFS client.  That is,
  we will only trust a positive name cache entry for a specified amount of
  time before falling back to a LOOKUP RPC, even if the ctime for the file
  handle matches the cached copy in the name cache entry.  The timeout is
  configured via a new 'nametimeo' mount option and defaults to 60 seconds.
  It may be set to zero to disable positive name caching entirely.
  
  Reviewed by:  rmacklem
  MFC after:    1 week

Modified:
  head/sbin/mount_nfs/mount_nfs.8
  head/sys/fs/nfsclient/nfs_clvfsops.c
  head/sys/fs/nfsclient/nfs_clvnops.c
  head/sys/fs/nfsclient/nfsmount.h
  head/sys/nfsclient/nfs_vfsops.c
  head/sys/nfsclient/nfs_vnops.c
  head/sys/nfsclient/nfsmount.h

Modified: head/sbin/mount_nfs/mount_nfs.8
==============================================================================
--- head/sbin/mount_nfs/mount_nfs.8     Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sbin/mount_nfs/mount_nfs.8     Wed Jan 25 20:05:58 2012        
(r230547)
@@ -157,6 +157,10 @@ Force the mount protocol to use UDP tran
 (Necessary for some old
 .Bx
 servers.)
+.It Cm nametimeo Ns = Ns Aq Ar value
+Override the default of NFS_DEFAULT_NAMETIMEO for the timeout (in seconds)
+for positive name cache entries.
+If this is set to 0 it disables positive name caching for the mount point.
 .It Cm negnametimeo Ns = Ns Aq Ar value
 Override the default of NFS_DEFAULT_NEGNAMETIMEO for the timeout (in seconds)
 for negative name cache entries. If this is set to 0 it disables negative

Modified: head/sys/fs/nfsclient/nfs_clvfsops.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clvfsops.c        Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/fs/nfsclient/nfs_clvfsops.c        Wed Jan 25 20:05:58 2012        
(r230547)
@@ -104,7 +104,7 @@ static void nfs_decode_args(struct mount
 static int     mountnfs(struct nfs_args *, struct mount *,
                    struct sockaddr *, char *, u_char *, int, u_char *, int,
                    u_char *, int, struct vnode **, struct ucred *,
-                   struct thread *, int);
+                   struct thread *, int, int);
 static void    nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
                    struct sockaddr_storage *, int *, off_t *,
                    struct timeval *);
@@ -520,7 +520,8 @@ nfs_mountdiskless(char *path,
                dirlen = 0;
        nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
        if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
-           NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
+           NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 
+           NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
                printf("nfs_mountroot: mount %s on /: %d\n", path, error);
                return (error);
        }
@@ -715,7 +716,7 @@ static const char *nfs_opts[] = { "from"
     "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
     "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
     "principal", "nfsv4", "gssname", "allgssname", "dirpath",
-    "negnametimeo", "nocto", "wcommitsize",
+    "nametimeo", "negnametimeo", "nocto", "wcommitsize",
     NULL };
 
 /*
@@ -760,6 +761,7 @@ nfs_mount(struct mount *mp)
        char hst[MNAMELEN];
        u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
        char *opt, *name, *secname;
+       int nametimeo = NFS_DEFAULT_NAMETIMEO;
        int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
        int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
        size_t hstlen;
@@ -968,6 +970,14 @@ nfs_mount(struct mount *mp)
                }
                args.flags |= NFSMNT_TIMEO;
        }
+       if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
+               ret = sscanf(opt, "%d", &nametimeo);
+               if (ret != 1 || nametimeo < 0) {
+                       vfs_mount_error(mp, "illegal nametimeo: %s", opt);
+                       error = EINVAL;
+                       goto out;
+               }
+       }
        if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
            == 0) {
                ret = sscanf(opt, "%d", &negnametimeo);
@@ -1126,7 +1136,7 @@ nfs_mount(struct mount *mp)
        args.fh = nfh;
        error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
            dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
-           negnametimeo);
+           nametimeo, negnametimeo);
 out:
        if (!error) {
                MNT_ILOCK(mp);
@@ -1170,7 +1180,7 @@ static int
 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
     char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
     u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
-    struct ucred *cred, struct thread *td, int negnametimeo)
+    struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
 {
        struct nfsmount *nmp;
        struct nfsnode *np;
@@ -1237,13 +1247,14 @@ mountnfs(struct nfs_args *argp, struct m
        }
        vfs_getnewfsid(mp);
        nmp->nm_mountp = mp;
-       mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);     
                
+       mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
 
        /*
-        * Since nfs_decode_args() might optionally set them, these need to
-        * set to defaults before the call, so that the optional settings
-        * aren't overwritten.
+        * Since nfs_decode_args() might optionally set them, these
+        * need to be set to defaults before the call, so that the
+        * optional settings aren't overwritten.
         */
+       nmp->nm_nametimeo = nametimeo;
        nmp->nm_negnametimeo = negnametimeo;
        nmp->nm_timeo = NFS_TIMEO;
        nmp->nm_retry = NFS_RETRANS;

Modified: head/sys/fs/nfsclient/nfs_clvnops.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clvnops.c Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/fs/nfsclient/nfs_clvnops.c Wed Jan 25 20:05:58 2012        
(r230547)
@@ -1063,7 +1063,8 @@ nfs_lookup(struct vop_lookup_args *ap)
                 * We only accept a positive hit in the cache if the
                 * change time of the file matches our cached copy.
                 * Otherwise, we discard the cache entry and fallback
-                * to doing a lookup RPC.
+                * to doing a lookup RPC.  We also only trust cache
+                * entries for less than nm_nametimeo seconds.
                 *
                 * To better handle stale file handles and attributes,
                 * clear the attribute cache of this node if it is a
@@ -1085,7 +1086,8 @@ nfs_lookup(struct vop_lookup_args *ap)
                        mtx_unlock(&newnp->n_mtx);
                }
                if (nfscl_nodeleg(newvp, 0) == 0 ||
-                   (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
+                   ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) &&
+                   VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
                    timespeccmp(&vattr.va_ctime, &nctime, ==))) {
                        NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
                        if (cnp->cn_nameiop != LOOKUP &&

Modified: head/sys/fs/nfsclient/nfsmount.h
==============================================================================
--- head/sys/fs/nfsclient/nfsmount.h    Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/fs/nfsclient/nfsmount.h    Wed Jan 25 20:05:58 2012        
(r230547)
@@ -66,6 +66,7 @@ struct        nfsmount {
        u_int64_t nm_maxfilesize;       /* maximum file size */
        int     nm_tprintf_initial_delay; /* initial delay */
        int     nm_tprintf_delay;       /* interval for messages */
+       int     nm_nametimeo;           /* timeout for +ve entries (sec) */
        int     nm_negnametimeo;        /* timeout for -ve entries (sec) */
 
        /* Newnfs additions */
@@ -106,6 +107,10 @@ struct     nfsmount {
  */
 #define        VFSTONFS(mp)    ((struct nfsmount *)((mp)->mnt_data))
 
+#ifndef NFS_DEFAULT_NAMETIMEO
+#define NFS_DEFAULT_NAMETIMEO          60
+#endif
+
 #ifndef NFS_DEFAULT_NEGNAMETIMEO
 #define NFS_DEFAULT_NEGNAMETIMEO       60
 #endif

Modified: head/sys/nfsclient/nfs_vfsops.c
==============================================================================
--- head/sys/nfsclient/nfs_vfsops.c     Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/nfsclient/nfs_vfsops.c     Wed Jan 25 20:05:58 2012        
(r230547)
@@ -117,7 +117,7 @@ static void nfs_decode_args(struct mount
                    struct nfs_args *argp, const char *hostname);
 static int     mountnfs(struct nfs_args *, struct mount *,
                    struct sockaddr *, char *, struct vnode **,
-                   struct ucred *cred, int);
+                   struct ucred *cred, int, int);
 static void    nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
                    struct sockaddr_storage *, int *, off_t *,
                    struct timeval *);
@@ -559,8 +559,8 @@ nfs_mountdiskless(char *path,
        int error;
 
        nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
-       if ((error = mountnfs(args, mp, nam, path, vpp,
-           td->td_ucred, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
+       if ((error = mountnfs(args, mp, nam, path, vpp, td->td_ucred,
+           NFS_DEFAULT_NAMETIMEO, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
                printf("nfs_mountroot: mount %s on /: %d\n", path, error);
                return (error);
        }
@@ -788,6 +788,7 @@ static const char *nfs_opts[] = { "from"
     "wsize", "rsize", "retrans", "acregmin", "acregmax", "acdirmin",
     "acdirmax", "deadthresh", "hostname", "timeout", "addr", "fh", "nfsv3",
     "sec", "maxgroups", "principal", "negnametimeo", "nocto", "wcommitsize",
+    "nametimeo",
     NULL };
 
 /*
@@ -836,6 +837,7 @@ nfs_mount(struct mount *mp)
        size_t len;
        u_char nfh[NFSX_V3FHMAX];
        char *opt;
+       int nametimeo = NFS_DEFAULT_NAMETIMEO;
        int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
 
        has_nfs_args_opt = 0;
@@ -1058,6 +1060,14 @@ nfs_mount(struct mount *mp)
                }
                args.flags |= NFSMNT_MAXGRPS;
        }
+       if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
+               ret = sscanf(opt, "%d", &nametimeo);
+               if (ret != 1 || nametimeo < 0) {
+                       vfs_mount_error(mp, "illegal nametimeo: %s", opt);
+                       error = EINVAL;
+                       goto out;
+               }
+       }
        if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
            == 0) {
                ret = sscanf(opt, "%d", &negnametimeo);
@@ -1182,7 +1192,7 @@ nfs_mount(struct mount *mp)
                goto out;
        }
        error = mountnfs(&args, mp, nam, args.hostname, &vp,
-           curthread->td_ucred, negnametimeo);
+           curthread->td_ucred, nametimeo, negnametimeo);
 out:
        if (!error) {
                MNT_ILOCK(mp);
@@ -1224,7 +1234,8 @@ nfs_cmount(struct mntarg *ma, void *data
  */
 static int
 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
-    char *hst, struct vnode **vpp, struct ucred *cred, int negnametimeo)
+    char *hst, struct vnode **vpp, struct ucred *cred, int nametimeo,
+    int negnametimeo)
 {
        struct nfsmount *nmp;
        struct nfsnode *np;
@@ -1274,6 +1285,7 @@ mountnfs(struct nfs_args *argp, struct m
        nmp->nm_numgrps = NFS_MAXGRPS;
        nmp->nm_readahead = NFS_DEFRAHEAD;
        nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
+       nmp->nm_nametimeo = nametimeo;
        nmp->nm_negnametimeo = negnametimeo;
        nmp->nm_tprintf_delay = nfs_tprintf_delay;
        if (nmp->nm_tprintf_delay < 0)

Modified: head/sys/nfsclient/nfs_vnops.c
==============================================================================
--- head/sys/nfsclient/nfs_vnops.c      Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/nfsclient/nfs_vnops.c      Wed Jan 25 20:05:58 2012        
(r230547)
@@ -959,7 +959,8 @@ nfs_lookup(struct vop_lookup_args *ap)
                 * We only accept a positive hit in the cache if the
                 * change time of the file matches our cached copy.
                 * Otherwise, we discard the cache entry and fallback
-                * to doing a lookup RPC.
+                * to doing a lookup RPC.  We also only trust cache
+                * entries for less than nm_nametimeo seconds.
                 *
                 * To better handle stale file handles and attributes,
                 * clear the attribute cache of this node if it is a
@@ -980,7 +981,8 @@ nfs_lookup(struct vop_lookup_args *ap)
                        KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
                        mtx_unlock(&newnp->n_mtx);
                }
-               if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
+               if ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) &&
+                   VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
                    timespeccmp(&vattr.va_ctime, &nctime, ==)) {
                        nfsstats.lookupcache_hits++;
                        if (cnp->cn_nameiop != LOOKUP &&

Modified: head/sys/nfsclient/nfsmount.h
==============================================================================
--- head/sys/nfsclient/nfsmount.h       Wed Jan 25 18:49:11 2012        
(r230546)
+++ head/sys/nfsclient/nfsmount.h       Wed Jan 25 20:05:58 2012        
(r230547)
@@ -83,6 +83,7 @@ struct        nfsmount {
        struct rpc_timers nm_timers[NFS_MAX_TIMER]; /* RTT Timers for rpcs */
        char    nm_principal[MNAMELEN]; /* GSS-API principal of server */
        gss_OID nm_mech_oid;            /* OID of selected GSS-API mechanism */
+       int     nm_nametimeo;           /* timeout for +ve entries (sec) */
        int     nm_negnametimeo;        /* timeout for -ve entries (sec) */
 
        /* NFSv4 */
@@ -116,6 +117,10 @@ struct     nfsmount {
 #define NFS_TPRINTF_DELAY               30
 #endif
 
+#ifndef NFS_DEFAULT_NAMETIMEO
+#define NFS_DEFAULT_NAMETIMEO          60
+#endif
+
 #ifndef NFS_DEFAULT_NEGNAMETIMEO
 #define NFS_DEFAULT_NEGNAMETIMEO       60
 #endif
_______________________________________________
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