svn commit: r192156 - in stable/7/sys: . contrib/pf dev/ath/ath_hal
dev/cxgb kern nfsclient sys
John Baldwin
jhb at FreeBSD.org
Fri May 15 20:36:55 UTC 2009
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);
More information about the svn-src-stable
mailing list