PERFORCE change 181847 for review
Gleb Kurtsou
gk at FreeBSD.org
Wed Aug 4 19:35:27 UTC 2010
http://p4web.freebsd.org/@@181847?ac=10
Change 181847 by gk at gk_h1 on 2010/08/04 19:35:09
Weak only cache support
Affected files ...
.. //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#9 edit
.. //depot/projects/soc2010/gk_namecache/sys/modules/tmpfs/Makefile#5 edit
.. //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#9 edit
Differences ...
==== //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#9 (text+ko) ====
@@ -54,6 +54,7 @@
#define DC_NAMEROUND 32 /* power of 2 */
#define DC_OP_LOCKPREF 0x00000001
+#define DC_OP_CREATEREF 0x00000002
#define DP_UNUSED_MIN 512
#define DP_THRESHOLD_DFLT 256
@@ -86,11 +87,14 @@
struct dircache_mount {
struct mtx dm_mtx;
struct dircache_idtree dm_idhead;
+ TAILQ_HEAD(, dircache_ref) dm_weakhead;
struct dircache_ref *dm_rootref;
struct dircache_ref *dm_negativeref;
u_long dm_idcnt;
};
+typedef int dc_filter_t(struct dircache *dc);
+
static struct dircache * dc_use(struct dircache *dc);
static int dc_rele(struct dircache *dc);
@@ -199,6 +203,7 @@
DC_STAT_DEFINE(clearunused_restart, "");
DC_STAT_DEFINE(clearinvalid, "");
+#define dm_assertlock(dm, w) mtx_assert(&(dm)->dm_mtx, (w))
#define dm_lock(dm) mtx_lock(&(dm)->dm_mtx)
#define dm_unlock(dm) mtx_unlock(&(dm)->dm_mtx)
@@ -295,10 +300,42 @@
RB_GENERATE_STATIC(dircache_idtree, dircache_ref, dr_idtree, dr_cmp);
+static __inline void
+dr_mntq_insert(struct dircache_ref *dr)
+{
+ struct dircache_mount *dm;
+ struct dircache_ref *col;
+
+ dm = dr->dr_mount;
+ dm_assertlock(dm, MA_OWNED);
+
+ if (dr->dr_id != 0) {
+ col = RB_INSERT(dircache_idtree, &dm->dm_idhead, dr);
+ MPASS(col == NULL);
+ } else
+ TAILQ_INSERT_HEAD(&dm->dm_weakhead, dr, dr_weaklist);
+ dm->dm_idcnt++;
+}
+
+static __inline void
+dr_mntq_remove(struct dircache_ref *dr)
+{
+ struct dircache_mount *dm;
+
+ dm = dr->dr_mount;
+ dm_assertlock(dm, MA_OWNED);
+
+ if (dr->dr_id != 0)
+ RB_REMOVE(dircache_idtree, &dm->dm_idhead, dr);
+ else
+ TAILQ_REMOVE(&dm->dm_weakhead, dr, dr_weaklist);
+ dm->dm_idcnt--;
+}
+
static struct dircache_ref *
dr_alloc(struct dircache_mount *dm, struct vnode *vp, uint64_t id)
{
- struct dircache_ref *dr, *col;
+ struct dircache_ref *dr;
dr = uma_zalloc(dircache_ref_zone, M_WAITOK | M_ZERO);
mtx_init(&dr->dr_mtx, "dircache ref", NULL, MTX_DEF | MTX_DUPOK);
@@ -308,13 +345,9 @@
dr->dr_vnode = vp;
if (vp != NULL)
MPASS(dm_get(vp) == dr->dr_mount);
- if (id != 0) {
- dm_lock(dm);
- col = RB_INSERT(dircache_idtree, &dm->dm_idhead, dr);
- dm->dm_idcnt++;
- MPASS(col == NULL);
- dm_unlock(dm);
- }
+ dm_lock(dm);
+ dr_mntq_insert(dr);
+ dm_unlock(dm);
return (dr);
}
@@ -331,9 +364,9 @@
MPASS(RB_EMPTY(&dr->dr_children));
dr_unlock(dr);
dm_lock(dm);
- RB_REMOVE(dircache_idtree, &dm->dm_idhead, dr);
- dm->dm_idcnt--;
+ dr_mntq_remove(dr);
dm_unlock(dm);
+ mtx_destroy(&dr->dr_mtx);
uma_zfree(dircache_ref_zone, dr);
} else
dr_unlock(dr);
@@ -341,14 +374,20 @@
}
static struct dircache_ref *
-dr_get(struct vnode *vp)
+dr_get(struct vnode *vp, int flags)
{
struct dircache_ref *dr;
dr = vp->v_dircache;
- MPASS(dr != NULL);
- dr_lock(dr);
- MPASS(vp->v_dircache == dr);
+ if (dr == NULL && (flags & DC_OP_CREATEREF) != 0 &&
+ (vp->v_mount->mnt_kern_flag & MNTK_DIRCACHE) == 0) {
+ dircache_allocvnode(vp, 0);
+ dr = vp->v_dircache;
+ }
+ if (dr != NULL) {
+ dr_lock(dr);
+ MPASS(vp->v_dircache == dr);
+ }
return (dr);
}
@@ -358,8 +397,7 @@
struct dircache *dc;
dc = LIST_FIRST(&dr->dr_entries);
- MPASS(dc != NULL);
- MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
+ MPASS(dc == NULL || LIST_NEXT(dc, dc_reflist) == NULL);
return (dc);
}
@@ -367,7 +405,12 @@
static __inline struct dircache_ref *
dr_parentref(struct dircache_ref *dr)
{
- return (dr_singleentry(dr)->dc_parentref);
+ struct dircache *dc;
+
+ dc = dr_singleentry(dr);
+ if (dc != NULL)
+ return (dc->dc_parentref);
+ return (NULL);
}
static void
@@ -536,6 +579,7 @@
DCDEBUG("drop: %p usecnt=%d holdcnt=%d-1\n", dc, dc->dc_usecnt,
dc->dc_holdcnt);
+ dc_assertlock(dc, islocked ? MA_OWNED : MA_NOTOWNED);
if (refcount_release(&dc->dc_holdcnt) != 0) {
MPASS(dc->dc_usecnt == 0);
if (islocked != 0) {
@@ -599,9 +643,11 @@
dr_assertlock(dr, MA_OWNED);
dc = dr_singleentry(dr);
- dc_lock(dc);
- dc_use(dc);
- dc_unlock(dc);
+ if (dc != NULL) {
+ dc_lock(dc);
+ dc_use(dc);
+ dc_unlock(dc);
+ }
}
static int
@@ -634,6 +680,8 @@
struct dircache *dc;
dc = dr_singleentry(dr);
+ if (dc == NULL)
+ return (0);
dc_lock(dc);
return (dc_rele(dc));
}
@@ -665,7 +713,7 @@
struct dircache_ref *dr;
struct dircache *dc;
- dr = dr_get(vp);
+ dr = dr_get(vp, DC_OP_CREATEREF);
dc = LIST_FIRST(&dr->dr_entries);
if (dc == NULL) {
dr_unlock(dr);
@@ -725,7 +773,7 @@
struct dircache_ref *parentref;
struct dircache *dc;
- parentref = dr_get(dvp);
+ parentref = dr_get(dvp, DC_OP_CREATEREF);
dc_initname(&key, cnp->cn_nameptr, cnp->cn_namelen);
dc = RB_FIND(dircache_tree, &parentref->dr_children, &key);
@@ -749,7 +797,7 @@
}
}
-static void dr_removechildren(struct dircache_ref *ref);
+static void dc_removechildren(struct dircache_ref *ref);
static void
dc_removeentry(struct dircache *dc, int flags)
@@ -776,7 +824,7 @@
dr_lock(selfref);
if (!RB_EMPTY(&selfref->dr_children))
- dr_removechildren(selfref);
+ dc_removechildren(selfref);
dr_remove(selfref, dc);
dc_rele_byref(parentref);
if ((flags & DC_OP_LOCKPREF) == 0)
@@ -808,7 +856,7 @@
dc_unlock(dc);
dr_lock(selfref);
- dr_removechildren(selfref);
+ dc_removechildren(selfref);
dr_remove(selfref, dc);
dr_lock(negativeref);
@@ -822,7 +870,26 @@
}
static void
-dr_removechildren(struct dircache_ref *ref)
+dc_detachentry(struct dircache *dc)
+{
+ struct dircache_ref *parentref;
+
+ MPASS(dc->dc_parentref != NULL);
+ dc_assertlock(dc, MA_OWNED);
+ dr_assertlock(dc->dc_parentref, MA_OWNED);
+
+ DCDEBUG("detach entry: %p %s\n", dc, dc->dc_name);
+ parentref = dc->dc_parentref;
+ dc->dc_parentref = NULL;
+ RB_REMOVE(dircache_tree, &parentref->dr_children, dc);
+ dc_invalidate(dc);
+
+ dc_rele_byref(parentref);
+ dc_droplocked(dc);
+}
+
+static void
+dc_removechildren(struct dircache_ref *ref)
{
struct dircache *child;
@@ -891,6 +958,58 @@
}
static void
+dc_purge(struct vnode *vp, dc_filter_t *filter)
+{
+ struct dircache_ref *parentref, *dr;
+ struct dircache *dc;
+
+ DC_ASSERT_WEAK(vp);
+
+restart:
+ dr = dr_get(vp, 0);
+ if (dr == NULL)
+ return;
+ RB_FOREACH(dc, dircache_tree, &dr->dr_children) {
+ dr_assertlock(dr, MA_OWNED);
+ dc_lock(dc);
+ if (filter == NULL || filter(dc) != 0)
+ dc_detachentry(dc);
+ else
+ dc_unlock(dc);
+ }
+ while (!LIST_EMPTY(&dr->dr_entries)) {
+ dc = LIST_FIRST(&dr->dr_entries);
+ if (filter != NULL && filter(dc) == 0)
+ continue;
+ parentref = dc->dc_parentref;
+ if (parentref != NULL) {
+ dc_hold(dc);
+ if (dr_trylock(parentref) == 0) {
+ dr_unlock(dr);
+ dr_lock(parentref);
+ } else
+ dr_unlock(dr);
+ dc_lock(dc);
+ if (dc->dc_parentref != parentref) {
+ dr_unlock(parentref);
+ dc_droplocked(dc);
+ goto restart;
+ }
+ dc_removeentry(dc, 0);
+ dc_drop(dc);
+ dr_lock(dr);
+ }
+ }
+ dr_unlock(dr);
+}
+
+static int
+dc_filternegative(struct dircache *dc)
+{
+ return (dc->dc_type == DT_NEGATIVE);
+}
+
+static void
dp_unused_insert(struct dircache *dc)
{
dc_assertlock(dc, MA_OWNED);
@@ -1041,6 +1160,7 @@
M_WAITOK | M_ZERO);
mtx_init(&dm->dm_mtx, "dircache mount", NULL, MTX_DEF);
RB_INIT(&dm->dm_idhead);
+ TAILQ_INIT(&dm->dm_weakhead);
dm->dm_negativeref = dr_alloc(dm, NULL, 0);
if (id != 0) {
MPASS((mp->mnt_kern_flag & MNTK_DIRCACHE) != 0);
@@ -1108,7 +1228,7 @@
}
childref = dr;
dr = dr_parentref(dr);
- dr_removechildren(childref);
+ dc_removechildren(childref);
if (dr != NULL) {
if (dr_trylock(dr) == 0) {
dr_unlock(childref);
@@ -1139,13 +1259,15 @@
mtx_unlock(&pool.dp_mtx);
dm_lock(dm);
- RB_REMOVE(dircache_idtree, &dm->dm_idhead, dm->dm_rootref);
- dm->dm_idcnt--;
+ dr_mntq_remove(dm->dm_rootref);
+ dr_mntq_remove(dm->dm_negativeref);
dm_unlock(dm);
uma_zfree(dircache_ref_zone, dm->dm_rootref);
uma_zfree(dircache_ref_zone, dm->dm_negativeref);
MPASS(RB_EMPTY(&dm->dm_idhead));
+ MPASS(TAILQ_EMPTY(&dm->dm_weakhead));
+ mtx_destroy(&dm->dm_mtx);
free(dm, M_DIRCACHE);
}
@@ -1197,17 +1319,20 @@
else if (cnp->cn_nameptr[0] == '.' && cnp->cn_nameptr[1] == '.' &&
cnp->cn_namelen == 2) {
MPASS((cnp->cn_flags & ISDOTDOT) != 0);
- parentref = dr_get(dvp);
+ parentref = dr_get(dvp, DC_OP_CREATEREF);
if (parentref != NULL) {
DCDEBUG("lookup dotdot: dvp=%p\n", dvp);
selfref = dr_parentref(parentref);
- *vpp = selfref->dr_vnode;
- if (*vpp != NULL)
- error = -1;
+ if (selfref != NULL) {
+ *vpp = selfref->dr_vnode;
+ if (*vpp != NULL)
+ error = -1;
+ } else
+ *vpp = NULL;
dr_unlock(parentref);
}
} else {
- dc = dc_find(dvp, cnp, 0);
+ dc = dc_find(dvp, cnp, DC_OP_LOCKPREF);
if (dc == NULL) {
DCDEBUG("lookup: not found: %s; dvp=%p; op=%ld\n",
cnp->cn_nameptr, dvp, cnp->cn_nameiop);
@@ -1217,6 +1342,8 @@
switch (cnp->cn_nameiop) {
case CREATE:
case RENAME:
+ dc_removeentry(dc, 0);
+ dc = NULL;
error = 0;
break;
default:
@@ -1230,9 +1357,13 @@
} else {
DC_STAT_INC(ds_miss);
}
- DCDEBUG("lookup: error=%d: %p %s; dvp=%p; op=%ld\n",
- error, dc, dc->dc_name, dvp, cnp->cn_nameiop);
- dc_unlock(dc);
+ DCDEBUG("lookup: error=%d: %p %.*s; dvp=%p; op=%ld\n",
+ error, dc, (int)cnp->cn_namelen, cnp->cn_nameptr,
+ dvp, cnp->cn_nameiop);
+ if (dc != NULL) {
+ dr_unlock(dc->dc_parentref);
+ dc_unlock(dc);
+ }
}
if (error == -1) {
@@ -1267,13 +1398,12 @@
struct dircache *rdc;
struct dircache_ref *selfref;
- DC_ASSERT_STRONG(dvp);
MPASS(type == DT_STRONG || type == DT_WEAK || type == DT_NEGATIVE);
ndc = dc_alloc(type, cnp->cn_nameptr, cnp->cn_namelen);
DCDEBUG("add: %s; vp=%p\n", cnp->cn_nameptr, vp);
- parentref = dr_get(dvp);
+ parentref = dr_get(dvp, DC_OP_CREATEREF);
dc_lock(ndc);
rdc = dc_insertentry(parentref, ndc);
dr_assertlock(parentref, MA_NOTOWNED); // XXX
@@ -1283,7 +1413,7 @@
selfref = dm_get(dvp)->dm_negativeref;
dr_lock(selfref);
} else {
- selfref = dr_get(vp);
+ selfref = dr_get(vp, DC_OP_CREATEREF);
dr_updategen(selfref);
}
MPASS(selfref != NULL);
@@ -1309,7 +1439,7 @@
DC_ASSERT_STRONG(dvp);
DCDEBUG("remove: %s; vp=%p\n", cnp->cn_nameptr, vp);
- parentref = dr_get(dvp);
+ parentref = dr_get(dvp, 0);
dc = dc_getentry(vp, cnp, parentref);
if (dc == NULL) {
DCDEBUG("remove: vp not found: %s vp=%p\n",
@@ -1354,7 +1484,7 @@
dc, dc->dc_name, dc->dc_parentref);
dc_removeentry(dc, 0);
} else {
- parentref = dr_get(tdvp);
+ parentref = dr_get(tdvp, 0);
dc_use_byref(parentref);
dr_unlock(parentref);
}
@@ -1448,21 +1578,26 @@
struct dircache_mount *dm;
struct dircache_ref *dr, key;
- DC_ASSERT_STRONG(vp);
MPASS(vp->v_type != VNON && vp->v_type != VBAD);
- MPASS(vp->v_dircache == NULL);
- MPASS(id != 0);
dm = dm_get(vp);
+ dr = NULL;
- dm_lock(dm);
- key.dr_id = id;
- dr = RB_FIND(dircache_idtree, &dm->dm_idhead, &key);
- dm_unlock(dm);
+ if (id != 0) {
+ MPASS(vp->v_dircache == NULL);
+ MPASS((vp->v_mount->mnt_kern_flag & MNTK_DIRCACHE) != 0);
+ dm_lock(dm);
+ key.dr_id = id;
+ dr = RB_FIND(dircache_idtree, &dm->dm_idhead, &key);
+ dm_unlock(dm);
+ } else if (vp->v_dircache != NULL) {
+ MPASS(vp->v_dircache->dr_id == id);
+ return;
+ }
if (dr == NULL)
- dr = dr_alloc(dm_get(vp), vp, id);
- else
+ dr = dr_alloc(dm, vp, id);
+ else if (id != 0)
DC_STAT_INC(ds_allocvnode_inode_hit);
DCDEBUG("alloc vnode: vp=%p; ino=%jd; dr=%p\n",
@@ -1470,10 +1605,18 @@
dr_lock(dr);
VI_LOCK(vp);
+ if (vp->v_dircache != NULL && vp->v_dircache != dr) {
+ /* Race should be possible only for weak entries. */
+ MPASS(id == 0);
+ dr_unlock(dr);
+ VI_UNLOCK(vp);
+ dr_drop(dr);
+ return;
+ }
MPASS(dr->dr_vnode == NULL || dr->dr_vnode == vp);
MPASS(vp->v_dircache == NULL || vp->v_dircache == dr);
+ dr->dr_vnode = vp;
vp->v_dircache = dr;
- dr->dr_vnode = vp;
VI_UNLOCK(vp);
LIST_FOREACH(dc, &dr->dr_entries, dc_reflist) {
dc_lock(dc);
@@ -1495,7 +1638,7 @@
struct dircache *dc;
struct dircache_ref *dr;
- dr = dr_get(vp);
+ dr = dr_get(vp, 0);
if (dr == NULL)
return;
@@ -1523,7 +1666,9 @@
struct dircache_ref *dr;
int error;
- dr = dr_get(vp);
+ dr = dr_get(vp, 0);
+ if (dr == NULL)
+ return (ENOENT);
dc = LIST_FIRST(&dr->dr_entries);
if (dc == NULL) {
dr_unlock(dr);
@@ -1552,7 +1697,7 @@
struct dircache_ref *dr;
u_long gen;
- dr = dr_get(vp);
+ dr = dr_get(vp, 0);
if (dr == NULL)
return (0);
gen = dr->dr_gen;
@@ -1568,14 +1713,12 @@
DC_ASSERT_WEAK(dvp);
-#if 0
- dr_initweak(dvp);
- dr_initweak(vp);
-#endif
+ dircache_allocvnode(dvp, 0);
- if (vp != NULL)
+ if (vp != NULL) {
+ dircache_allocvnode(vp, 0);
error = dircache_add(dvp, vp, cnp, DT_WEAK);
- else
+ } else
error = dircache_add(dvp, NULL, cnp, DT_NEGATIVE);
return (error);
@@ -1584,90 +1727,13 @@
void
dircache_purge(struct vnode *vp)
{
-#if 0
- struct dircache_ref *dr;
- struct dircache *dc;
-
- DC_ASSERT_WEAK(vp);
-
- dr = dr_get(vp);
- if (dr == NULL)
- return;
- while (!LIST_EMPTY(&dr->dr_entries)) {
- dc = LIST_FIRST(&dr->dr_entries);
- dc_lock(dc);
- dc_hold(dc);
- if (!RB_EMPTY(&dc->dc_children))
- dc_detachchildren(dc);
- dc_detacheentry(dc);
- dc_drop(dc);
- }
-#endif
+ dc_purge(vp, NULL);
}
void
dircache_purge_negative(struct vnode *vp)
{
-#if 0
- DC_ASSERT_WEAK(vp);
-
- dr = dr_get(vp);
- if (dr == NULL)
- return;
-#endif
-
-#if 0
- TAILQ_HEAD(, dircache) head = TAILQ_HEAD_INITIALIZER(head);
- struct dircache *dc, *child, *tmp;
- int r;
-
-restart:
- VI_LOCK(vp);
- dc = TAILQ_FIRST(&vp->v_dircache);
- if (dc == NULL) {
- VI_UNLOCK(vp);
- return;
- }
- if (vp->v_type == VDIR) {
- MPASS(TAILQ_NEXT(dc, dc_list) == NULL);
- if (dc_refinterlock(vp, dc) != 0)
- goto restart;
- dc_use(dc);
- RB_FOREACH_SAFE(child, dircache_tree, &dc->dc_children, tmp) {
- if (child->dc_type == DT_NEGATIVE) {
- RB_REMOVE(dircache_tree, &dc->dc_children,
- child);
- if (dc_trylock(child) != 0) {
- child->dc_parent = NULL;
- dc_droplocked(child);
- r = dc_relesafe(dc);
- MPASS(r == 0);
- } else
- TAILQ_INSERT_HEAD(&head, child,
- dc_tmplist);
- }
- }
- dc_unlock(dc);
- while(!TAILQ_EMPTY(&head)) {
- child = TAILQ_FIRST(&head);
- TAILQ_REMOVE(&head, child, dc_tmplist);
- dc_lock(child);
- MPASS(child->dc_parent == dc);
- dc_lock(dc);
- child->dc_parent = NULL;
- dc_droplocked(child);
- dc_rele(dc);
- }
- dc_lock(dc);
- dc_rele(dc);
- } else {
- /* Check invariants */
- TAILQ_FOREACH(dc, &vp->v_dircache, dc_list) {
- MPASS(dc->dc_type != DT_NEGATIVE);
- }
- VI_UNLOCK(vp);
- }
-#endif
+ dc_purge(vp, dc_filternegative);
}
==== //depot/projects/soc2010/gk_namecache/sys/modules/tmpfs/Makefile#5 (text+ko) ====
@@ -10,8 +10,8 @@
.if defined(NO_DIRCACHE)
DEBUG_FLAGS+= -DNO_DIRCACHE
-#.elif !defined(USE_DIRCACHE)
-#DEBUG_FLAGS+= -DDIRCACHE_WEAK
+.elif !defined(USE_DIRCACHE)
+DEBUG_FLAGS+= -DDIRCACHE_WEAK
.endif
.include <bsd.kmod.mk>
==== //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#9 (text+ko) ====
@@ -64,13 +64,19 @@
struct mtx dr_mtx;
struct dircache_tree dr_children;
LIST_HEAD(, dircache) dr_entries;
- RB_ENTRY(dircache_ref) dr_idtree;
+ union {
+ RB_ENTRY(dircache_ref) drl_idtree;
+ TAILQ_ENTRY(dircache_ref) drl_weaklist;
+ } dr_l;
struct vnode *dr_vnode;
struct dircache_mount *dr_mount;
uint64_t dr_id;
u_long dr_gen;
};
+#define dr_idtree dr_l.drl_idtree
+#define dr_weaklist dr_l.drl_weaklist
+
RB_HEAD(dircache_idtree, dircache_ref);
void dircache_init(struct mount *mp, uint64_t id);
More information about the p4-projects
mailing list