summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2009-10-23 19:52:29 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2009-10-23 19:52:29 +0000
commit115753ce9eb755279fea668547d1692b4ec06ddf (patch)
treed17238b7d63a224d245596220552884c70c4fe7e
parent1ca0e46fdfb82b931d25332101e5d56289794911 (diff)
Notes
-rw-r--r--sys/nfsclient/nfs_vnops.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 7dfd298da6d2..dc619275aeac 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -924,6 +924,7 @@ nfs_lookup(struct vop_lookup_args *ap)
struct vnode **vpp = ap->a_vpp;
struct mount *mp = dvp->v_mount;
struct vattr vattr;
+ time_t dmtime;
int flags = cnp->cn_flags;
struct vnode *newvp;
struct nfsmount *nmp;
@@ -935,7 +936,7 @@ nfs_lookup(struct vop_lookup_args *ap)
int error = 0, attrflag, fhsize, ltype;
int v3 = NFS_ISV3(dvp);
struct thread *td = cnp->cn_thread;
-
+
*vpp = NULLVP;
if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
@@ -992,6 +993,19 @@ nfs_lookup(struct vop_lookup_args *ap)
np->n_dmtime = 0;
mtx_unlock(&np->n_mtx);
}
+
+ /*
+ * Cache the modification time of the parent directory in case
+ * the lookup fails and results in adding the first negative
+ * name cache entry for the directory. Since this is reading
+ * a single time_t, don't bother with locking. The
+ * modification time may be a bit stale, but it must be read
+ * before performing the lookup RPC to prevent a race where
+ * another lookup updates the timestamp on the directory after
+ * the lookup RPC has been performed on the server but before
+ * n_dmtime is set at the end of this function.
+ */
+ dmtime = np->n_vattr.va_mtime.tv_sec;
error = 0;
newvp = NULLVP;
nfsstats.lookupcache_misses++;
@@ -1130,13 +1144,25 @@ nfsmout:
* Maintain n_dmtime as the modification time
* of the parent directory when the oldest -ve
* name cache entry for this directory was
- * added.
+ * added. If a -ve cache entry has already
+ * been added with a newer modification time
+ * by a concurrent lookup, then don't bother
+ * adding a cache entry. The modification
+ * time of the directory might have changed
+ * due to the file this lookup failed to find
+ * being created. In that case a subsequent
+ * lookup would incorrectly use the entry
+ * added here instead of doing an extra
+ * lookup.
*/
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);
+ if (np->n_dmtime <= dmtime) {
+ if (np->n_dmtime == 0)
+ np->n_dmtime = dmtime;
+ mtx_unlock(&np->n_mtx);
+ cache_enter(dvp, NULL, cnp);
+ } else
+ mtx_unlock(&np->n_mtx);
}
return (ENOENT);
}