Subject: Re: ufs-ism in lookup(9)
To: None <wrstuden@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 06/22/2004 23:00:37
--NextPart-20040622225109-0234600
Content-Type: Text/Plain; charset=us-ascii

hi,

> > I definitely think the "no way to see" aspect is bad. I think there may 
> > still be value in keeping the removal, but we definitely should let the fs 
> > know there was/is an entry.

i made a less-intrusive version. (attached)

it introduces a new function, cache_lookup_raw(), for
filesystems which want more flexibility.
otoh, it keeps cache_lookup() as-is so that filesystems which prefer
the current "kind" behaviour won't need to be changed.

is it acceptable for you?

YAMAMOTO Takashi

--NextPart-20040622225109-0234600
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="a.diff"

Index: sys/namei.h
===================================================================
--- sys/namei.h	(revision 671)
+++ sys/namei.h	(working copy)
@@ -193,6 +193,8 @@ void cache_purge1 __P((struct vnode *, c
 #define	PURGE_CHILDREN	2
 #define	cache_purge(vp)	cache_purge1((vp), NULL, PURGE_PARENTS|PURGE_CHILDREN)
 int cache_lookup __P((struct vnode *, struct vnode **, struct componentname *));
+int cache_lookup_raw __P((struct vnode *, struct vnode **,
+    struct componentname *));
 int cache_revlookup __P((struct vnode *, struct vnode **, char **, char *));
 void cache_enter __P((struct vnode *, struct vnode *, struct componentname *));
 void nchinit __P((void));
Index: kern/vfs_cache.c
===================================================================
--- kern/vfs_cache.c	(revision 766)
+++ kern/vfs_cache.c	(working copy)
@@ -328,6 +328,77 @@ fail:
 	return (-1);
 }
 
+int
+cache_lookup_raw(struct vnode *dvp, struct vnode **vpp,
+    struct componentname *cnp)
+{
+	struct namecache *ncp;
+	struct vnode *vp;
+	int error;
+
+	if (!doingcache) {
+		cnp->cn_flags &= ~MAKEENTRY;
+		*vpp = NULL;
+		return (-1);
+	}
+
+	if (cnp->cn_namelen > NCHNAMLEN) {
+		/* XXXSMP - updating stats without lock; do we care? */
+		nchstats.ncs_long++;
+		cnp->cn_flags &= ~MAKEENTRY;
+		goto fail;
+	}
+	simple_lock(&namecache_slock);
+	ncp = cache_lookup_entry(dvp, cnp);
+	if (ncp == NULL) {
+		nchstats.ncs_miss++;
+		goto fail_wlock;
+	}
+	/*
+	 * Move this slot to end of LRU chain,
+	 * if not already there.
+	 */
+	if (TAILQ_NEXT(ncp, nc_lru) != 0) {
+		TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
+		TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
+	}
+
+	vp = ncp->nc_vp;
+	if (vp == NULL) {
+		/*
+		 * Restore the ISWHITEOUT flag saved earlier.
+		 */
+		cnp->cn_flags |= ncp->nc_flags;
+		nchstats.ncs_neghits++;
+		simple_unlock(&namecache_slock);
+		return (ENOENT);
+	}
+
+	error = vget(vp, LK_NOWAIT);
+
+	/* Release the name cache mutex while we get reference to the vnode */
+	simple_unlock(&namecache_slock);
+
+	if (error) {
+		KASSERT(error == EBUSY);
+		/*
+		 * this vnode is being cleaned out.
+		 */
+		nchstats.ncs_falsehits++; /* XXX badhits? */
+		goto fail;
+	}
+
+	*vpp = vp;
+
+	return 0;
+
+fail_wlock:
+	simple_unlock(&namecache_slock);
+fail:
+	*vpp = NULL;
+	return -1;
+}
+
 /*
  * Scan cache looking for name of directory entry pointing at vp.
  *
--NextPart-20040622225109-0234600
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="n.diff"

Index: nfs/nfs_vnops.c
===================================================================
--- nfs/nfs_vnops.c	(revision 766)
+++ nfs/nfs_vnops.c	(working copy)
@@ -888,7 +888,9 @@ nfs_lookup(v)
 	 * the time the cache entry has been created. If it has,
 	 * the cache entry has to be ignored. 
 	 */
-	if ((error = cache_lookup(dvp, vpp, cnp)) >= 0) {
+	error = cache_lookup_raw(dvp, vpp, cnp);
+	KASSERT(dvp != *vpp);
+	if (error >= 0) {
 		struct vattr vattr;
 		int err2;
 
@@ -897,23 +899,10 @@ nfs_lookup(v)
 			return error;
 		}
 
-		if (cnp->cn_flags & PDIRUNLOCK) {
-			err2 = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
-			if (err2 != 0) {
-				*vpp = NULLVP;
-				return err2;
-			}
-			cnp->cn_flags &= ~PDIRUNLOCK;
-		}
-
 		err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
 		if (err2 != 0) {
-			if (error == 0) {
-				if (*vpp != dvp)
-					vput(*vpp);
-				else
-					vrele(*vpp);
-			}
+			if (error == 0)
+				vrele(*vpp);
 			*vpp = NULLVP;
 			return err2;
 		}
@@ -921,8 +910,9 @@ nfs_lookup(v)
 		if (error == ENOENT) {
 			if (!VOP_GETATTR(dvp, &vattr, cnp->cn_cred,
 			    cnp->cn_proc) && timespeccmp(&vattr.va_mtime,
-			    &VTONFS(dvp)->n_nctime, ==))
-				return ENOENT;
+			    &VTONFS(dvp)->n_nctime, ==)) {
+				goto noentry;
+			}
 			cache_purge1(dvp, NULL, PURGE_CHILDREN);
 			timespecclear(&np->n_nctime);
 			goto dorpc;
@@ -930,24 +920,38 @@ nfs_lookup(v)
 
 		newvp = *vpp;
 		if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
-			&& vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime)
-		{
+		    && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
 			nfsstats.lookupcache_hits++;
-			if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
-				cnp->cn_flags |= SAVENAME;
-			if ((!lockparent || !(flags & ISLASTCN)) &&	
-			     newvp != dvp) {
+			if ((flags & ISDOTDOT) != 0 ||
+			    (~flags & (LOCKPARENT|ISLASTCN)) != 0) {
 				VOP_UNLOCK(dvp, 0);
 				cnp->cn_flags |= PDIRUNLOCK;
 			}
+			error = vn_lock(newvp, LK_EXCLUSIVE);
+			if (error) {
+				/* newvp has been revoked. */
+				vrele(newvp);
+				*vpp = NULL;
+				return error;
+			}
+			if ((~flags & (LOCKPARENT|ISLASTCN)) == 0
+			    && (cnp->cn_flags & PDIRUNLOCK)) {
+				KASSERT(flags & ISDOTDOT);
+				error = vn_lock(dvp, LK_EXCLUSIVE);
+				if (error) {
+					vput(newvp);
+					*vpp = NULL;
+					return error;
+				}
+				cnp->cn_flags &= ~PDIRUNLOCK;
+			}
+			if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+				cnp->cn_flags |= SAVENAME;
 			KASSERT(newvp->v_type != VNON);
 			return (0);
 		}
 		cache_purge1(newvp, NULL, PURGE_PARENTS);
-		if (newvp != dvp)
-			vput(newvp);
-		else
-			vrele(newvp);
+		vrele(newvp);
 		*vpp = NULLVP;
 	}
 dorpc:
@@ -1114,15 +1118,16 @@ dorpc:
 			if (newvp != dvp)
 				VOP_UNLOCK(newvp, 0);
 		}
+noentry:
 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
 		    (flags & ISLASTCN) && error == ENOENT) {
-			if (dvp->v_mount->mnt_flag & MNT_RDONLY)
+			if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
 				error = EROFS;
-			else
+			} else {
 				error = EJUSTRETURN;
+				cnp->cn_flags |= SAVENAME;
+			}
 		}
-		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
-			cnp->cn_flags |= SAVENAME;
 		*vpp = NULL;
 		return error;
 	}
@@ -1684,10 +1689,14 @@ nfs_mknod(v)
 		struct componentname *a_cnp;
 		struct vattr *a_vap;
 	} */ *ap = v;
+	struct vnode *dvp = ap->a_dvp;
+	struct componentname *cnp = ap->a_cnp;
 	int error;
 
-	error = nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
-	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+	error = nfs_mknodrpc(dvp, ap->a_vpp, cnp, ap->a_vap);
+	VN_KNOTE(dvp, NOTE_WRITE);
+	if (error == 0 || error == EEXIST)
+		cache_purge1(dvp, cnp, 0);
 	return (error);
 }
 
@@ -1789,14 +1798,19 @@ again:
 			fmode &= ~O_EXCL;
 			goto again;
 		}
-		if (newvp)
-			vput(newvp);
 	} else if (v3 && (fmode & O_EXCL))
 		error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
-	if (!error) {
+	if (error == 0) {
 		if (cnp->cn_flags & MAKEENTRY)
 			nfs_cache_enter(dvp, newvp, cnp);
+		else
+			cache_purge1(dvp, cnp, 0);
 		*ap->a_vpp = newvp;
+	} else {
+		if (newvp)
+			vput(newvp);
+		if (error == EEXIST)
+			cache_purge1(dvp, cnp, 0);
 	}
 	PNBUF_PUT(cnp->cn_pnbuf);
 	VTONFS(dvp)->n_flag |= NMODIFIED;
@@ -2000,10 +2014,15 @@ nfs_rename(v)
 
 	VN_KNOTE(fdvp, NOTE_WRITE);
 	VN_KNOTE(tdvp, NOTE_WRITE);
-	if (fvp->v_type == VDIR) {
+	if (error == 0 || error == EEXIST) {
+		if (fvp->v_type == VDIR)
+			cache_purge(fvp);
+		else
+			cache_purge1(fdvp, fcnp, 0);
 		if (tvp != NULL && tvp->v_type == VDIR)
-			cache_purge(tdvp);
-		cache_purge(fdvp);
+			cache_purge(tvp);
+		else
+			cache_purge1(tdvp, tcnp, 0);
 	}
 out:
 	if (tdvp == tvp)
@@ -2155,6 +2174,8 @@ nfs_link(v)
 	}
 #endif
 	nfsm_reqdone;
+	if (error == 0 || error == EEXIST)
+		cache_purge1(dvp, cnp, 0);
 	PNBUF_PUT(cnp->cn_pnbuf);
 	VTONFS(dvp)->n_flag |= NMODIFIED;
 	if (!attrflag)
@@ -2241,6 +2262,8 @@ nfs_symlink(v)
 	 */
 	if (rexmit && error == EEXIST)
 		error = 0;
+	if (error == 0 || error == EEXIST)
+		cache_purge1(dvp, cnp, 0);
 	if (error == 0 && newvp == NULL) {
 		struct nfsnode *np = NULL;
 

--NextPart-20040622225109-0234600--