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); + } } /* _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"