Subject: cache_purge
To: None <tech-kern@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 03/20/2004 16:03:36
--NextPart-20040320154242-0151500
Content-Type: Text/Plain; charset=us-ascii

hi,

currently cache_purge() is a sledgehammer that purge all entries
related the given vnode.
the attached diff (cache_purge1.diff) makes it a little more controlable.
eg. purge only an entry, only child entries, etc.
i'd like to commit it if there's no objection.

YAMAMOTO Takashi

--NextPart-20040320154242-0151500
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="cache_purge1.diff"

Index: sys/namei.h
===================================================================
--- sys/namei.h	(revision 630)
+++ sys/namei.h	(revision 640)
@@ -189,6 +189,10 @@ uint32_t namei_hash __P((const char *, c
 int	lookup __P((struct nameidata *));
 int	relookup __P((struct vnode *, struct vnode **, struct componentname *));
 void cache_purge __P((struct vnode *));
+void cache_purge1 __P((struct vnode *, const struct componentname *, int));
+#define	PURGE_PARENTS	1
+#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_revlookup __P((struct vnode *, struct vnode **, char **, char *));
 void cache_enter __P((struct vnode *, struct vnode *, struct componentname *));
Index: kern/vfs_cache.c
===================================================================
--- kern/vfs_cache.c	(revision 630)
+++ kern/vfs_cache.c	(revision 640)
@@ -96,6 +96,8 @@ static struct simplelock namecache_slock
 
 static void cache_remove(struct namecache *);
 static void cache_free(struct namecache *);
+static __inline struct namecache *cache_lookup_entry(
+    const struct vnode *, const struct componentname *);
 
 static void
 cache_remove(struct namecache *ncp)
@@ -133,6 +135,26 @@ cache_free(struct namecache *ncp)
 	numcache--; /* XXX MP */
 }
 
+static __inline struct namecache *
+cache_lookup_entry(const struct vnode *dvp, const struct componentname *cnp)
+{
+	struct nchashhead *ncpp;
+	struct namecache *ncp;
+
+	LOCK_ASSERT(simple_lock_held(&namecache_slock));
+
+	ncpp = &nchashtbl[NCHASH(cnp, dvp)];
+
+	LIST_FOREACH(ncp, ncpp, nc_hash) {
+		if (ncp->nc_dvp == dvp &&
+		    ncp->nc_nlen == cnp->cn_namelen &&
+		    !memcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
+			break;
+	}
+
+	return ncp;
+}
+
 /*
  * Look for a the name in the cache. We don't do this
  * if the segment name is long, simply so the cache can avoid
@@ -153,7 +175,6 @@ int
 cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
 {
 	struct namecache *ncp;
-	struct nchashhead *ncpp;
 	struct vnode *vp;
 	int error;
 
@@ -169,15 +190,9 @@ cache_lookup(struct vnode *dvp, struct v
 		cnp->cn_flags &= ~MAKEENTRY;
 		goto fail;
 	}
-	ncpp = &nchashtbl[NCHASH(cnp, dvp)];
 	simple_lock(&namecache_slock);
-	LIST_FOREACH(ncp, ncpp, nc_hash) {
-		if (ncp->nc_dvp == dvp &&
-		    ncp->nc_nlen == cnp->cn_namelen &&
-		    !memcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
-			break;
-	}
-	if (ncp == 0) {
+	ncp = cache_lookup_entry(dvp, cnp);
+	if (ncp == NULL) {
 		nchstats.ncs_miss++;
 		goto fail_wlock;
 	}
@@ -304,14 +319,8 @@ remove:
 	 * the cache entry is invalid, or otherwise don't
 	 * want cache entry to exist.
 	 */
-	TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
-	LIST_REMOVE(ncp, nc_hash);
-	ncp->nc_hash.le_prev = NULL;
-	if (ncp->nc_vhash.le_prev != NULL) {
-		LIST_REMOVE(ncp, nc_vhash);
-		ncp->nc_vhash.le_prev = NULL;
-	}
-	TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru);
+	cache_remove(ncp);
+	cache_free(ncp);
 
 fail_wlock:
 	simple_unlock(&namecache_slock);
@@ -408,6 +417,7 @@ cache_enter(struct vnode *dvp, struct vn
 	 * Free the cache slot at head of lru chain.
 	 */
 	simple_lock(&namecache_slock);
+	KASSERT(cache_lookup_entry(dvp, cnp) == NULL);
 	if (numcache < numvnodes) {
 		numcache++;
 		simple_unlock(&namecache_slock);
@@ -529,20 +539,33 @@ nchreinit(void)
  * hide entries that would now be invalid
  */
 void
-cache_purge(struct vnode *vp)
+cache_purge1(struct vnode *vp, const struct componentname *cnp, int flags)
 {
 	struct namecache *ncp, *ncnext;
 
 	simple_lock(&namecache_slock);
-	for (ncp = LIST_FIRST(&vp->v_nclist); ncp != NULL; ncp = ncnext) {
-		ncnext = LIST_NEXT(ncp, nc_vlist);
-		cache_remove(ncp);
-		cache_free(ncp);
+	if (flags & PURGE_PARENTS) {
+		for (ncp = LIST_FIRST(&vp->v_nclist); ncp != NULL;
+		    ncp = ncnext) {
+			ncnext = LIST_NEXT(ncp, nc_vlist);
+			cache_remove(ncp);
+			cache_free(ncp);
+		}
 	}
-	for (ncp = LIST_FIRST(&vp->v_dnclist); ncp != NULL; ncp = ncnext) {
-		ncnext = LIST_NEXT(ncp, nc_dvlist);
-		cache_remove(ncp);
-		cache_free(ncp);
+	if (flags & PURGE_CHILDREN) {
+		for (ncp = LIST_FIRST(&vp->v_dnclist); ncp != NULL;
+		    ncp = ncnext) {
+			ncnext = LIST_NEXT(ncp, nc_dvlist);
+			cache_remove(ncp);
+			cache_free(ncp);
+		}
+	}
+	if (cnp != NULL) {
+		ncp = cache_lookup_entry(vp, cnp);
+		if (ncp) {
+			cache_remove(ncp);
+			cache_free(ncp);
+		}
 	}
 	simple_unlock(&namecache_slock);
 }

--NextPart-20040320154242-0151500--