summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient/nfs_vnops.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-02-19 22:28:48 +0000
committerjhb <jhb@FreeBSD.org>2009-02-19 22:28:48 +0000
commit5dc7ef7e69e7552a62f396a484740c12642918df (patch)
tree789787a3459d38eece091c20561b1d47a4875bec /sys/nfsclient/nfs_vnops.c
parent508874f4299bd6840631dde45b0eb6bc8b29a3d9 (diff)
downloadFreeBSD-src-5dc7ef7e69e7552a62f396a484740c12642918df.zip
FreeBSD-src-5dc7ef7e69e7552a62f396a484740c12642918df.tar.gz
Enable caching of negative pathname lookups in the NFS client. To avoid
stale entries, we save a copy of the directory's modification time when the first negative cache entry was added in the directory's NFS node. When a negative cache entry is hit during a pathname lookup, the parent directory's modification time is checked. If it has changed, all of the negative cache entries for that parent are purged and the lookup falls back to using the RPC. This required adding a new cache_purge_negative() method to the name cache to purge only negative cache entries for a given directory. Submitted by: mohans, Rick Macklem, Ricardo Labiaga @ NetApp Reviewed by: mohans
Diffstat (limited to 'sys/nfsclient/nfs_vnops.c')
-rw-r--r--sys/nfsclient/nfs_vnops.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 90400cc..dbdf5cb 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -852,6 +852,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;
@@ -880,8 +881,12 @@ 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)
&& vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
@@ -897,6 +902,24 @@ 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) == 0 &&
+ vattr.va_mtime.tv_sec == np->n_dmtime) {
+ nfsstats.lookupcache_hits++;
+ if ((cnp->cn_nameiop == CREATE ||
+ cnp->cn_nameiop == RENAME) &&
+ (flags & ISLASTCN))
+ cnp->cn_flags |= SAVENAME;
+ return (ENOENT);
+ }
+ cache_purge_negative(dvp);
+ np->n_dmtime = 0;
}
error = 0;
newvp = NULLVP;
@@ -982,16 +1005,38 @@ 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.
+ */
+ if (np->n_dmtime == 0)
+ np->n_dmtime = np->n_vattr.va_mtime.tv_sec;
+ cache_enter(dvp, NULL, cnp);
+ }
+ return (ENOENT);
}
+done:
return (error);
}
OpenPOWER on IntegriCloud