diff options
author | Mateusz Guzik <mjg@FreeBSD.org> | 2019-11-27 01:21:42 +0000 |
---|---|---|
committer | Mateusz Guzik <mjg@FreeBSD.org> | 2019-11-27 01:21:42 +0000 |
commit | 588e69e2fde146bab5ea3600f3d13a457ba318f2 (patch) | |
tree | 37dec287e11b28dd6ca719350622b8d809fb0957 | |
parent | 2ac930e32cbca7710789bde0738dde73923bada5 (diff) | |
download | src-588e69e2fde146bab5ea3600f3d13a457ba318f2.tar.gz src-588e69e2fde146bab5ea3600f3d13a457ba318f2.zip |
cache: stop reusing .. entries on enter
It almost never happens in practice anyway. With this eliminated ->nc_vp
cannot change vnodes, removing an obstacle on the road to lockless
lookup.
Notes
Notes:
svn path=/head/; revision=355125
-rw-r--r-- | sys/kern/vfs_cache.c | 91 |
1 files changed, 34 insertions, 57 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 5666f7b30e85..6787d4d4af81 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -1661,6 +1661,33 @@ cache_enter_unlock(struct celockstate *cel) cache_unlock_vnodes_cel(cel); } +static void __noinline +cache_enter_dotdot_prep(struct vnode *dvp, struct vnode *vp, + struct componentname *cnp) +{ + struct celockstate cel; + struct namecache *ncp; + uint32_t hash; + int len; + + if (dvp->v_cache_dd == NULL) + return; + len = cnp->cn_namelen; + cache_celockstate_init(&cel); + hash = cache_get_hash(cnp->cn_nameptr, len, dvp); + cache_enter_lock_dd(&cel, dvp, vp, hash); + ncp = dvp->v_cache_dd; + if (ncp != NULL && (ncp->nc_flag & NCF_ISDOTDOT)) { + KASSERT(ncp->nc_dvp == dvp, ("wrong isdotdot parent")); + cache_zap_locked(ncp, false); + } else { + ncp = NULL; + } + dvp->v_cache_dd = NULL; + cache_enter_unlock(&cel); + cache_free(ncp); +} + /* * Add an entry to the cache. */ @@ -1672,11 +1699,10 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, struct namecache *ncp, *n2, *ndd; struct namecache_ts *ncp_ts, *n2_ts; struct nchashhead *ncpp; - struct neglist *neglist; uint32_t hash; int flag; int len; - bool neg_locked, held_dvp; + bool held_dvp; u_long lnumcache; CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr); @@ -1690,65 +1716,12 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, return; #endif - cache_celockstate_init(&cel); - ndd = NULL; - ncp_ts = NULL; flag = 0; - if (cnp->cn_nameptr[0] == '.') { + if (__predict_false(cnp->cn_nameptr[0] == '.')) { if (cnp->cn_namelen == 1) return; if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { - len = cnp->cn_namelen; - hash = cache_get_hash(cnp->cn_nameptr, len, dvp); - cache_enter_lock_dd(&cel, dvp, vp, hash); - /* - * If dotdot entry already exists, just retarget it - * to new parent vnode, otherwise continue with new - * namecache entry allocation. - */ - if ((ncp = dvp->v_cache_dd) != NULL && - ncp->nc_flag & NCF_ISDOTDOT) { - KASSERT(ncp->nc_dvp == dvp, - ("wrong isdotdot parent")); - neg_locked = false; - if (ncp->nc_flag & NCF_NEGATIVE || vp == NULL) { - neglist = NCP2NEGLIST(ncp); - mtx_lock(&ncneg_hot.nl_lock); - mtx_lock(&neglist->nl_lock); - neg_locked = true; - } - if (!(ncp->nc_flag & NCF_NEGATIVE)) { - TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, - ncp, nc_dst); - } else { - cache_negative_remove(ncp, true); - } - if (vp != NULL) { - TAILQ_INSERT_HEAD(&vp->v_cache_dst, - ncp, nc_dst); - if (ncp->nc_flag & NCF_HOTNEGATIVE) - numhotneg--; - ncp->nc_flag &= ~(NCF_NEGATIVE|NCF_HOTNEGATIVE); - } else { - if (ncp->nc_flag & NCF_HOTNEGATIVE) { - numhotneg--; - ncp->nc_flag &= ~(NCF_HOTNEGATIVE); - } - ncp->nc_flag |= NCF_NEGATIVE; - cache_negative_insert(ncp, true); - } - if (neg_locked) { - mtx_unlock(&neglist->nl_lock); - mtx_unlock(&ncneg_hot.nl_lock); - } - ncp->nc_vp = vp; - cache_enter_unlock(&cel); - return; - } - dvp->v_cache_dd = NULL; - cache_enter_unlock(&cel); - cache_celockstate_init(&cel); - SDT_PROBE3(vfs, namecache, enter, done, dvp, "..", vp); + cache_enter_dotdot_prep(dvp, vp, cnp); flag = NCF_ISDOTDOT; } } @@ -1762,6 +1735,10 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, return; } + cache_celockstate_init(&cel); + ndd = NULL; + ncp_ts = NULL; + held_dvp = false; if (LIST_EMPTY(&dvp->v_cache_src) && flag != NCF_ISDOTDOT) { vhold(dvp); |