Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Sep 2016 16:52:14 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r305386 - head/sys/kern
Message-ID:  <201609041652.u84GqE5s037275@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Sun Sep  4 16:52:14 2016
New Revision: 305386
URL: https://svnweb.freebsd.org/changeset/base/305386

Log:
  cache: defer freeing entries until after the global lock is dropped
  
  This also defers vdrop for held vnodes.
  
  Glanced at by:	kib

Modified:
  head/sys/kern/vfs_cache.c

Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c	Sun Sep  4 15:08:14 2016	(r305385)
+++ head/sys/kern/vfs_cache.c	Sun Sep  4 16:52:14 2016	(r305386)
@@ -131,6 +131,7 @@ struct	namecache_ts {
 #define NCF_ISDOTDOT	0x02
 #define	NCF_TS		0x04
 #define	NCF_DTS		0x08
+#define	NCF_DVDROP	0x10
 
 /*
  * Name caching works as follows:
@@ -227,6 +228,8 @@ cache_free(struct namecache *ncp)
 	if (ncp == NULL)
 		return;
 	ts = ncp->nc_flag & NCF_TS;
+	if ((ncp->nc_flag & NCF_DVDROP) != 0)
+		vdrop(ncp->nc_dvp);
 	if (ncp->nc_nlen <= CACHE_PATH_CUTOFF) {
 		if (ts)
 			uma_zfree(cache_zone_small_ts, ncp);
@@ -476,7 +479,7 @@ cache_negative_remove(struct namecache *
 	numneg--;
 }
 
-static void
+static struct namecache *
 cache_negative_zap_one(void)
 {
 	struct namecache *ncp;
@@ -486,6 +489,7 @@ cache_negative_zap_one(void)
 	KASSERT(ncp->nc_vp == NULL, ("ncp %p vp %p on ncneg",
 	    ncp, ncp->nc_vp));
 	cache_zap(ncp);
+	return (ncp);
 }
 
 /*
@@ -497,7 +501,6 @@ cache_negative_zap_one(void)
 static void
 cache_zap(struct namecache *ncp)
 {
-	struct vnode *vp;
 
 	rw_assert(&cache_lock, RA_WLOCKED);
 	CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp);
@@ -508,7 +511,6 @@ cache_zap(struct namecache *ncp)
 		SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp,
 		    nc_get_name(ncp));
 	}
-	vp = NULL;
 	LIST_REMOVE(ncp, nc_hash);
 	if (ncp->nc_flag & NCF_ISDOTDOT) {
 		if (ncp == ncp->nc_dvp->v_cache_dd)
@@ -516,7 +518,7 @@ cache_zap(struct namecache *ncp)
 	} else {
 		LIST_REMOVE(ncp, nc_src);
 		if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
-			vp = ncp->nc_dvp;
+			ncp->nc_flag |= NCF_DVDROP;
 			numcachehv--;
 		}
 	}
@@ -528,9 +530,6 @@ cache_zap(struct namecache *ncp)
 		cache_negative_remove(ncp);
 	}
 	numcache--;
-	cache_free(ncp);
-	if (vp != NULL)
-		vdrop(vp);
 }
 
 /*
@@ -611,10 +610,14 @@ retry_wlocked:
 			if ((cnp->cn_flags & MAKEENTRY) == 0) {
 				if (!wlocked && !CACHE_UPGRADE_LOCK())
 					goto wlock;
-				if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT)
-					cache_zap(dvp->v_cache_dd);
+				ncp = NULL;
+				if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT) {
+					ncp = dvp->v_cache_dd;
+					cache_zap(ncp);
+				}
 				dvp->v_cache_dd = NULL;
 				CACHE_WUNLOCK();
+				cache_free(ncp);
 				return (0);
 			}
 			ncp = dvp->v_cache_dd;
@@ -666,6 +669,7 @@ retry_wlocked:
 			goto wlock;
 		cache_zap(ncp);
 		CACHE_WUNLOCK();
+		cache_free(ncp);
 		return (0);
 	}
 
@@ -689,6 +693,7 @@ negative_success:
 			goto wlock;
 		cache_zap(ncp);
 		CACHE_WUNLOCK();
+		cache_free(ncp);
 		return (0);
 	}
 
@@ -767,7 +772,7 @@ void
 cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
     struct timespec *tsp, struct timespec *dtsp)
 {
-	struct namecache *ncp, *n2;
+	struct namecache *ncp, *n2, *ndd, *nneg;
 	struct namecache_ts *n3;
 	struct nchashhead *ncpp;
 	uint32_t hash;
@@ -789,6 +794,7 @@ cache_enter_time(struct vnode *dvp, stru
 	if (numcache >= desiredvnodes * ncsizefactor)
 		return;
 
+	ndd = nneg = NULL;
 	flag = 0;
 	if (cnp->cn_nameptr[0] == '.') {
 		if (cnp->cn_namelen == 1)
@@ -905,9 +911,12 @@ cache_enter_time(struct vnode *dvp, stru
 				 * directory name in it and the name ".." for the
 				 * directory's parent.
 				 */
-				if ((n2 = vp->v_cache_dd) != NULL &&
-				    (n2->nc_flag & NCF_ISDOTDOT) != 0)
-					cache_zap(n2);
+				if ((ndd = vp->v_cache_dd) != NULL) {
+					if ((ndd->nc_flag & NCF_ISDOTDOT) != 0)
+						cache_zap(ndd);
+					else
+						ndd = NULL;
+				}
 				vp->v_cache_dd = ncp;
 			}
 		} else {
@@ -945,8 +954,10 @@ cache_enter_time(struct vnode *dvp, stru
 		    nc_get_name(ncp));
 	}
 	if (numneg * ncnegfactor > numcache)
-		cache_negative_zap_one();
+		nneg = cache_negative_zap_one();
 	CACHE_WUNLOCK();
+	cache_free(ndd);
+	cache_free(nneg);
 }
 
 /*
@@ -1034,21 +1045,35 @@ cache_changesize(int newmaxvnodes)
 void
 cache_purge(struct vnode *vp)
 {
+	TAILQ_HEAD(, namecache) ncps;
+	struct namecache *ncp, *nnp;
 
 	CTR1(KTR_VFS, "cache_purge(%p)", vp);
 	SDT_PROBE1(vfs, namecache, purge, done, vp);
+	TAILQ_INIT(&ncps);
 	CACHE_WLOCK();
-	while (!LIST_EMPTY(&vp->v_cache_src))
-		cache_zap(LIST_FIRST(&vp->v_cache_src));
-	while (!TAILQ_EMPTY(&vp->v_cache_dst))
-		cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
+	while (!LIST_EMPTY(&vp->v_cache_src)) {
+		ncp = LIST_FIRST(&vp->v_cache_src);
+		cache_zap(ncp);
+		TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst);
+	}
+	while (!TAILQ_EMPTY(&vp->v_cache_dst)) {
+		ncp = TAILQ_FIRST(&vp->v_cache_dst);
+		cache_zap(ncp);
+		TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst);
+	}
 	if (vp->v_cache_dd != NULL) {
-		KASSERT(vp->v_cache_dd->nc_flag & NCF_ISDOTDOT,
+		ncp = vp->v_cache_dd;
+		KASSERT(ncp->nc_flag & NCF_ISDOTDOT,
 		   ("lost dotdot link"));
-		cache_zap(vp->v_cache_dd);
+		cache_zap(ncp);
+		TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst);
 	}
 	KASSERT(vp->v_cache_dd == NULL, ("incomplete purge"));
 	CACHE_WUNLOCK();
+	TAILQ_FOREACH_SAFE(ncp, &ncps, nc_dst, nnp) {
+		cache_free(ncp);
+	}
 }
 
 /*
@@ -1057,16 +1082,23 @@ cache_purge(struct vnode *vp)
 void
 cache_purge_negative(struct vnode *vp)
 {
-	struct namecache *cp, *ncp;
+	TAILQ_HEAD(, namecache) ncps;
+	struct namecache *ncp, *nnp;
 
 	CTR1(KTR_VFS, "cache_purge_negative(%p)", vp);
 	SDT_PROBE1(vfs, namecache, purge_negative, done, vp);
+	TAILQ_INIT(&ncps);
 	CACHE_WLOCK();
-	LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) {
-		if (cp->nc_vp == NULL)
-			cache_zap(cp);
+	LIST_FOREACH_SAFE(ncp, &vp->v_cache_src, nc_src, nnp) {
+		if (ncp->nc_vp != NULL)
+			continue;
+		cache_zap(ncp);
+		TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst);
 	}
 	CACHE_WUNLOCK();
+	TAILQ_FOREACH_SAFE(ncp, &ncps, nc_dst, nnp) {
+		cache_free(ncp);
+	}
 }
 
 /*
@@ -1075,19 +1107,26 @@ cache_purge_negative(struct vnode *vp)
 void
 cache_purgevfs(struct mount *mp)
 {
+	TAILQ_HEAD(, namecache) ncps;
 	struct nchashhead *ncpp;
 	struct namecache *ncp, *nnp;
 
 	/* Scan hash tables for applicable entries */
 	SDT_PROBE1(vfs, namecache, purgevfs, done, mp);
+	TAILQ_INIT(&ncps);
 	CACHE_WLOCK();
 	for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
 		LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) {
-			if (ncp->nc_dvp->v_mount == mp)
-				cache_zap(ncp);
+			if (ncp->nc_dvp->v_mount != mp)
+				continue;
+			cache_zap(ncp);
+			TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst);
 		}
 	}
 	CACHE_WUNLOCK();
+	TAILQ_FOREACH_SAFE(ncp, &ncps, nc_dst, nnp) {
+		cache_free(ncp);
+	}
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201609041652.u84GqE5s037275>