svn commit: r305386 - head/sys/kern
Mateusz Guzik
mjg at FreeBSD.org
Sun Sep 4 16:52:15 UTC 2016
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);
+ }
}
/*
More information about the svn-src-head
mailing list