summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient/nfs_clvnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clvnops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c87
1 files changed, 38 insertions, 49 deletions
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 8bc0be9..2747191 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1016,12 +1016,12 @@ nfs_lookup(struct vop_lookup_args *ap)
struct vnode *newvp;
struct nfsmount *nmp;
struct nfsnode *np, *newnp;
- int error = 0, attrflag, dattrflag, ltype;
+ int error = 0, attrflag, dattrflag, ltype, ncticks;
struct thread *td = cnp->cn_thread;
struct nfsfh *nfhp;
struct nfsvattr dnfsva, nfsva;
struct vattr vattr;
- struct timespec dmtime;
+ struct timespec nctime;
*vpp = NULLVP;
if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
@@ -1042,11 +1042,24 @@ nfs_lookup(struct vop_lookup_args *ap)
if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0)
return (error);
- error = cache_lookup(dvp, vpp, cnp);
+ error = cache_lookup_times(dvp, vpp, cnp, &nctime, &ncticks);
if (error > 0 && error != ENOENT)
return (error);
if (error == -1) {
/*
+ * Lookups of "." are special and always return the
+ * current directory. cache_lookup() already handles
+ * associated locking bookkeeping, etc.
+ */
+ if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
+ /* XXX: Is this really correct? */
+ if (cnp->cn_nameiop != LOOKUP &&
+ (flags & ISLASTCN))
+ cnp->cn_flags |= SAVENAME;
+ return (0);
+ }
+
+ /*
* 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
@@ -1073,7 +1086,7 @@ nfs_lookup(struct vop_lookup_args *ap)
}
if (nfscl_nodeleg(newvp, 0) == 0 ||
(VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
- timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==))) {
+ timespeccmp(&vattr.va_ctime, &nctime, ==))) {
NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
if (cnp->cn_nameiop != LOOKUP &&
(flags & ISLASTCN))
@@ -1092,36 +1105,21 @@ nfs_lookup(struct vop_lookup_args *ap)
/*
* 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. We also
- * only trust -ve cache entries for less than
- * nm_negative_namecache_timeout seconds.
+ * the cached copy in the name cache entry.
+ * Otherwise, we discard all of the negative cache
+ * entries for this directory. We also only trust
+ * negative cache entries for up to nm_negnametimeo
+ * seconds.
*/
- if ((u_int)(ticks - np->n_dmtime_ticks) <
- (nmp->nm_negnametimeo * hz) &&
+ if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) &&
VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
- timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) {
+ timespeccmp(&vattr.va_mtime, &nctime, ==)) {
NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
return (ENOENT);
}
cache_purge_negative(dvp);
- mtx_lock(&np->n_mtx);
- timespecclear(&np->n_dmtime);
- 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.na_mtime;
error = 0;
newvp = NULLVP;
NFSINCRGLOBAL(newnfsstats.lookupcache_misses);
@@ -1157,30 +1155,22 @@ nfs_lookup(struct vop_lookup_args *ap)
return (EJUSTRETURN);
}
- if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) {
+ if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE &&
+ dattrflag) {
/*
- * Maintain n_dmtime as the modification time
- * of the parent directory when the oldest -ve
- * name cache entry for this directory was
- * 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.
+ * Cache the modification time of the parent
+ * directory from the post-op attributes in
+ * the name cache entry. The negative cache
+ * entry will be ignored once the directory
+ * has changed. Don't bother adding the entry
+ * if the directory has already changed.
*/
mtx_lock(&np->n_mtx);
- if (timespeccmp(&np->n_dmtime, &dmtime, <=)) {
- if (!timespecisset(&np->n_dmtime)) {
- np->n_dmtime = dmtime;
- np->n_dmtime_ticks = ticks;
- }
+ if (timespeccmp(&np->n_vattr.na_mtime,
+ &dnfsva.na_mtime, ==)) {
mtx_unlock(&np->n_mtx);
- cache_enter(dvp, NULL, cnp);
+ cache_enter_time(dvp, NULL, cnp,
+ &dnfsva.na_mtime);
} else
mtx_unlock(&np->n_mtx);
}
@@ -1279,9 +1269,8 @@ nfs_lookup(struct vop_lookup_args *ap)
if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
if ((cnp->cn_flags & MAKEENTRY) &&
- (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
- np->n_ctime = np->n_vattr.na_vattr.va_ctime;
- cache_enter(dvp, newvp, cnp);
+ (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) && attrflag) {
+ cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime);
}
*vpp = newvp;
return (0);
OpenPOWER on IntegriCloud