aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2019-11-27 01:21:42 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2019-11-27 01:21:42 +0000
commit588e69e2fde146bab5ea3600f3d13a457ba318f2 (patch)
tree37dec287e11b28dd6ca719350622b8d809fb0957
parent2ac930e32cbca7710789bde0738dde73923bada5 (diff)
downloadsrc-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.c91
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);