Author: jhb
Date: Fri May 15 20:36:54 2009
New Revision: 192156
URL: http://svn.freebsd.org/changeset/base/192156

Log:
  MFC: Add caching of -ve lookups to the NFS client.  To prevent clients from
  not noticing new files created by another client for a "long" time, reduce
  the default timeout for caching attributes of directories from 30 seconds
  to 3 seconds.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/kern/vfs_cache.c
  stable/7/sys/nfsclient/nfs.h
  stable/7/sys/nfsclient/nfs_vnops.c
  stable/7/sys/nfsclient/nfsnode.h
  stable/7/sys/sys/vnode.h

Modified: stable/7/sys/kern/vfs_cache.c
==============================================================================
--- stable/7/sys/kern/vfs_cache.c       Fri May 15 20:13:15 2009        
(r192155)
+++ stable/7/sys/kern/vfs_cache.c       Fri May 15 20:36:54 2009        
(r192156)
@@ -700,6 +700,24 @@ cache_purge(vp)
 }
 
 /*
+ * Invalidate all negative entries for a particular directory vnode.
+ */
+void
+cache_purge_negative(vp)
+       struct vnode *vp;
+{
+       struct namecache *cp, *ncp;
+
+       CTR1(KTR_VFS, "cache_purge_negative(%p)", vp);
+       CACHE_LOCK();
+       LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) {
+               if (cp->nc_vp == NULL)
+                       cache_zap(cp);
+       }
+       CACHE_UNLOCK();
+}
+
+/*
  * Flush all entries referencing a particular filesystem.
  */
 void

Modified: stable/7/sys/nfsclient/nfs.h
==============================================================================
--- stable/7/sys/nfsclient/nfs.h        Fri May 15 20:13:15 2009        
(r192155)
+++ stable/7/sys/nfsclient/nfs.h        Fri May 15 20:36:54 2009        
(r192156)
@@ -63,7 +63,7 @@
 #define        NFS_MAXATTRTIMO 60
 #endif
 #ifndef NFS_MINDIRATTRTIMO
-#define        NFS_MINDIRATTRTIMO 30           /* VDIR attrib cache timeout in 
sec */
+#define        NFS_MINDIRATTRTIMO 3            /* VDIR attrib cache timeout in 
sec */
 #endif
 #ifndef NFS_MAXDIRATTRTIMO
 #define        NFS_MAXDIRATTRTIMO 60

Modified: stable/7/sys/nfsclient/nfs_vnops.c
==============================================================================
--- stable/7/sys/nfsclient/nfs_vnops.c  Fri May 15 20:13:15 2009        
(r192155)
+++ stable/7/sys/nfsclient/nfs_vnops.c  Fri May 15 20:36:54 2009        
(r192156)
@@ -862,6 +862,7 @@ nfs_lookup(struct vop_lookup_args *ap)
        struct componentname *cnp = ap->a_cnp;
        struct vnode *dvp = ap->a_dvp;
        struct vnode **vpp = ap->a_vpp;
+       struct vattr vattr;
        int flags = cnp->cn_flags;
        struct vnode *newvp;
        struct nfsmount *nmp;
@@ -890,16 +891,20 @@ nfs_lookup(struct vop_lookup_args *ap)
        if (error > 0 && error != ENOENT)
                return (error);
        if (error == -1) {
-               struct vattr vattr;
-
+               /*
+                * 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.
+                */
                newvp = *vpp;
                if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, td)
-                && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
-                    nfsstats.lookupcache_hits++;
-                    if (cnp->cn_nameiop != LOOKUP &&
-                        (flags & ISLASTCN))
-                            cnp->cn_flags |= SAVENAME;
-                    return (0);
+                   && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
+                       nfsstats.lookupcache_hits++;
+                       if (cnp->cn_nameiop != LOOKUP &&
+                           (flags & ISLASTCN))
+                               cnp->cn_flags |= SAVENAME;
+                       return (0);
                }
                cache_purge(newvp);
                if (dvp != newvp)
@@ -907,6 +912,22 @@ nfs_lookup(struct vop_lookup_args *ap)
                else 
                        vrele(newvp);
                *vpp = NULLVP;
+       } else if (error == ENOENT) {
+               /*
+                * We only accept a negative hit in the cache if the
+                * modification time of the parent directory matches
+                * our cached copy.  Otherwise, we discard all of the
+                * negative cache entries for this directory.
+                */
+               if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred, td) == 0 &&
+                   vattr.va_mtime.tv_sec == np->n_dmtime) {
+                       nfsstats.lookupcache_hits++;
+                       return (ENOENT);
+               }
+               cache_purge_negative(dvp);
+               mtx_lock(&np->n_mtx);
+               np->n_dmtime = 0;
+               mtx_unlock(&np->n_mtx);
        }
        error = 0;
        newvp = NULLVP;
@@ -992,16 +1013,40 @@ nfsmout:
                        vput(newvp);
                        *vpp = NULLVP;
                }
+
+               if (error != ENOENT)
+                       goto done;
+
+               /* The requested file was not found. */
                if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
-                   (flags & ISLASTCN) && error == ENOENT) {
+                   (flags & ISLASTCN)) {
+                       /*
+                        * XXX: UFS does a full VOP_ACCESS(dvp,
+                        * VWRITE) here instead of just checking
+                        * MNT_RDONLY.
+                        */
                        if (dvp->v_mount->mnt_flag & MNT_RDONLY)
-                               error = EROFS;
-                       else
-                               error = EJUSTRETURN;
-               }
-               if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+                               return (EROFS);
                        cnp->cn_flags |= SAVENAME;
+                       return (EJUSTRETURN);
+               }
+
+               if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) {
+                       /*
+                        * Maintain n_dmtime as the modification time
+                        * of the parent directory when the oldest -ve
+                        * name cache entry for this directory was
+                        * added.
+                        */
+                       mtx_lock(&np->n_mtx);
+                       if (np->n_dmtime == 0)
+                               np->n_dmtime = np->n_vattr.va_mtime.tv_sec;
+                       mtx_unlock(&np->n_mtx);
+                       cache_enter(dvp, NULL, cnp);
+               }
+               return (ENOENT);
        }
+done:
        return (error);
 }
 

Modified: stable/7/sys/nfsclient/nfsnode.h
==============================================================================
--- stable/7/sys/nfsclient/nfsnode.h    Fri May 15 20:13:15 2009        
(r192155)
+++ stable/7/sys/nfsclient/nfsnode.h    Fri May 15 20:36:54 2009        
(r192156)
@@ -109,6 +109,7 @@ struct nfsnode {
        time_t                  n_modestamp;    /* mode cache timestamp */
        struct timespec         n_mtime;        /* Prev modify time. */
        time_t                  n_ctime;        /* Prev create time. */
+       time_t                  n_dmtime;       /* Prev dir modify time. */
        time_t                  n_expiry;       /* Lease expiry time */
        nfsfh_t                 *n_fhp;         /* NFS File Handle */
        struct vnode            *n_vnode;       /* associated vnode */

Modified: stable/7/sys/sys/vnode.h
==============================================================================
--- stable/7/sys/sys/vnode.h    Fri May 15 20:13:15 2009        (r192155)
+++ stable/7/sys/sys/vnode.h    Fri May 15 20:36:54 2009        (r192156)
@@ -564,6 +564,7 @@ void        cache_enter(struct vnode *dvp, stru
 int    cache_lookup(struct vnode *dvp, struct vnode **vpp,
            struct componentname *cnp);
 void   cache_purge(struct vnode *vp);
+void   cache_purge_negative(struct vnode *vp);
 void   cache_purgevfs(struct mount *mp);
 int    change_dir(struct vnode *vp, struct thread *td);
 int    change_root(struct vnode *vp, struct thread *td);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to