diff options
| author | John Baldwin <jhb@FreeBSD.org> | 2009-05-15 20:36:54 +0000 |
|---|---|---|
| committer | John Baldwin <jhb@FreeBSD.org> | 2009-05-15 20:36:54 +0000 |
| commit | a43e11c99c1375e73805e23c14866f5c8179b977 (patch) | |
| tree | 81754df31291b62d3bfeafefccbb1f3216226b40 /sys/nfsclient | |
| parent | 23b4046188963e6d9160aedc6e7f8c8bd4201072 (diff) | |
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.
Notes
svn path=/stable/7/; revision=192156
Diffstat (limited to 'sys/nfsclient')
| -rw-r--r-- | sys/nfsclient/nfs.h | 2 | ||||
| -rw-r--r-- | sys/nfsclient/nfs_vnops.c | 73 | ||||
| -rw-r--r-- | sys/nfsclient/nfsnode.h | 1 |
3 files changed, 61 insertions, 15 deletions
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index 9e524204bce3..2b09631c1065 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -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 diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index f91708601fee..ae12aad34c43 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -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); } diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h index 03f49267724c..118ecc6a2bf0 100644 --- a/sys/nfsclient/nfsnode.h +++ b/sys/nfsclient/nfsnode.h @@ -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 */ |
