PERFORCE change 181047 for review
Gleb Kurtsou
gk at FreeBSD.org
Fri Jul 16 12:22:28 UTC 2010
http://p4web.freebsd.org/@@181047?ac=10
Change 181047 by gk at gk_h1 on 2010/07/16 12:21:43
Refactor to use dircache_ref
Affected files ...
.. //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_subr.c#5 edit
.. //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vnops.c#5 edit
.. //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#6 edit
.. //depot/projects/soc2010/gk_namecache/sys/kern/vfs_subr.c#4 edit
.. //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#6 edit
.. //depot/projects/soc2010/gk_namecache/sys/sys/vnode.h#3 edit
Differences ...
==== //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_subr.c#5 (text+ko) ====
@@ -525,7 +525,7 @@
* cannot fail. */
tmpfs_dir_attach(dvp, de);
#ifndef NO_DIRCACHE
- dircache_add(dvp, *vpp, cnp, DT_STRONG, node->tn_id);
+ dircache_add(dvp, *vpp, cnp, DT_STRONG);
#endif
out:
==== //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vnops.c#5 (text+ko) ====
@@ -919,7 +919,7 @@
/* Insert the new directory entry into the appropriate directory. */
tmpfs_dir_attach(dvp, de);
#ifndef NO_DIRCACHE
- dircache_add(dvp, vp, cnp, DT_STRONG, node->tn_id);
+ dircache_add(dvp, vp, cnp, DT_STRONG);
#endif
/* vp link count has changed, so update node times. */
==== //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#6 (text+ko) ====
@@ -80,10 +80,14 @@
struct dircache_mount {
struct mtx dm_mtx;
- LIST_HEAD(, dircache) dm_inodehead;
- struct dircache *dm_entry;
+ LIST_HEAD(, dircache_ref) dm_inohead;
+ struct dircache_ref *dm_rootref;
+ struct dircache_ref *dm_negativeref;
};
+static struct dircache * dc_use(struct dircache *dc);
+static int dc_rele(struct dircache *dc);
+
static void dp_unused_insert(struct dircache *dc);
static void dp_unused_remove(struct dircache *dc);
static void dp_unused_lazyclear(void);
@@ -96,6 +100,7 @@
static MALLOC_DEFINE(M_DIRCACHE, "dircache buf", "dircache buffers");
static uma_zone_t dircache_zone;
+static uma_zone_t dircache_ref_zone;
static SYSCTL_NODE(_vfs, OID_AUTO, dircache, CTLFLAG_RW, 0, "Dircache");
static SYSCTL_NODE(_vfs_dircache, OID_AUTO, stats, CTLFLAG_RD, 0,
@@ -135,7 +140,6 @@
ds_reclaimvnode,
ds_alloc,
ds_free,
- ds_vinterlock_restart,
ds_lookup_restart,
ds_insert_restart,
ds_clearunused,
@@ -183,13 +187,24 @@
DC_STAT_DEFINE(reclaimvnode, "");
DC_STAT_DEFINE(alloc, "");
DC_STAT_DEFINE(free, "");
-DC_STAT_DEFINE(vinterlock_restart, "vnode interlock restarts");
DC_STAT_DEFINE(lookup_restart, "lookup restarts");
DC_STAT_DEFINE(insert_restart, "insert restarts");
DC_STAT_DEFINE(clearunused, "");
DC_STAT_DEFINE(clearunused_restart, "");
DC_STAT_DEFINE(clearinvalid, "");
+#define dm_lock(dm) mtx_lock(&(dm)->dm_mtx)
+#define dm_unlock(dm) mtx_unlock(&(dm)->dm_mtx)
+
+#define dr_assertlock(dr, w) mtx_assert(&(dr)->dr_mtx, (w))
+#define dr_lock(dr) mtx_lock(&(dr)->dr_mtx)
+#define dr_unlock(dr) mtx_unlock(&(dr)->dr_mtx)
+
+#define dc_lock(dc) mtx_lock(&(dc)->dc_mtx)
+#define dc_trylock(dc) mtx_trylock(&(dc)->dc_mtx)
+#define dc_unlock(dc) mtx_unlock(&(dc)->dc_mtx)
+#define dc_assertlock(dc, w) mtx_assert(&(dc)->dc_mtx, (w))
+
static void
dircache_sysinit(void *arg __unused)
{
@@ -209,6 +224,10 @@
sizeof(struct dircache), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
+ dircache_ref_zone = uma_zcreate("dircache ref",
+ sizeof(struct dircache_ref), NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, 0);
+
dc_tq = taskqueue_create("dircache tq", M_WAITOK,
taskqueue_thread_enqueue, &dc_tq);
taskqueue_start_threads(&dc_tq, 1, PWAIT, "dircache taskq");
@@ -223,19 +242,106 @@
MPASS(TAILQ_EMPTY(&pool.dp_invalid));
mtx_destroy(&pool.dp_mtx);
uma_zdestroy(dircache_zone);
+ uma_zdestroy(dircache_ref_zone);
}
SYSUNINIT(dircache, SI_SUB_VFS, SI_ORDER_SECOND, dircache_sysuninit, NULL);
-#define dm_lock(dm) mtx_lock(&(dm)->dm_mtx)
-
-#define dm_unlock(dm) mtx_unlock(&(dm)->dm_mtx)
-
static __inline struct dircache_mount *
dm_get(struct vnode *vp)
{
return (vp->v_mount->mnt_dircache);
}
+static struct dircache_ref *
+dr_alloc(struct dircache_mount *dm, struct vnode *vp, ino_t ino)
+{
+ struct dircache_ref *dr;
+
+ dr = uma_zalloc(dircache_ref_zone, M_WAITOK | M_ZERO);
+ mtx_init(&dr->dr_mtx, "dircache ref", NULL, MTX_DEF);
+ LIST_INIT(&dr->dr_entries);
+ dr->dr_ino = ino;
+ dr->dr_mount = dm;
+ dr->dr_vnode = vp;
+ if (vp != NULL)
+ MPASS(dm_get(vp) == dr->dr_mount);
+ if (ino != 0) {
+ dm_lock(dm);
+ LIST_INSERT_HEAD(&dm->dm_inohead, dr, dr_inolist);
+ dm_unlock(dm);
+ }
+
+ return (dr);
+}
+
+static __inline void
+dr_drop(struct dircache_ref *dr)
+{
+ struct dircache_mount *dm = dr->dr_mount;
+
+ mtx_assert(&dr->dr_mtx, MA_OWNED);
+
+ if (dr->dr_vnode == NULL && LIST_EMPTY(&dr->dr_entries) &&
+ dr != dm->dm_rootref && dr != dm->dm_negativeref) {
+ dr_unlock(dr);
+ dm_lock(dm);
+ LIST_REMOVE(dr, dr_inolist);
+ dm_unlock(dm);
+ uma_zfree(dircache_ref_zone, dr);
+ } else
+ dr_unlock(dr);
+
+}
+
+static struct dircache_ref *
+dr_get(struct vnode *vp)
+{
+ struct dircache_ref *dr;
+
+restart:
+ dr = vp->v_dircache;
+ if (dr == NULL)
+ return (NULL);
+ dr_lock(dr);
+ if (vp->v_dircache != dr) {
+ dr_unlock(dr);
+ goto restart;
+ }
+
+ return (dr);
+}
+
+static void
+dr_add(struct dircache_ref *dr, struct dircache *dc)
+{
+ dr_assertlock(dr, MA_OWNED);
+
+ MPASS(dc->dc_ref == NULL);
+ dc->dc_ref = dr;
+ DCDEBUG("add ref: vp=%p dc=%p dr=%p\n",
+ dr->dr_vnode, dc, dr);
+ if (dr->dr_vnode != NULL && dr->dr_vnode->v_type == VDIR)
+ KASSERT(LIST_EMPTY(&dr->dr_entries),
+ ("dircache: multiple directory vnode references %p",
+ dr->dr_vnode));
+ LIST_INSERT_HEAD(&dr->dr_entries, dc, dc_reflist);
+ if (dr->dr_vnode != NULL)
+ dc_use(dc);
+}
+
+static void
+dr_remove(struct dircache_ref *dr, struct dircache *dc)
+{
+ MPASS(dc->dc_ref == NULL);
+
+ LIST_REMOVE(dc, dc_reflist);
+ if (dr->dr_vnode != NULL) {
+ dc_lock(dc);
+ dc_rele(dc);
+ }
+ dr_drop(dr);
+}
+
static __inline int
dc_cmpname(struct dircache *dc, char *name, u_int namelen)
{
@@ -265,14 +371,6 @@
RB_GENERATE_STATIC(dircache_tree, dircache, dc_tree, dc_cmp);
-#define dc_lock(dc) mtx_lock(&(dc)->dc_mtx)
-
-#define dc_trylock(dc) mtx_trylock(&(dc)->dc_mtx)
-
-#define dc_unlock(dc) mtx_unlock(&(dc)->dc_mtx)
-
-#define dc_assertlock(dc, w) mtx_assert(&(dc)->dc_mtx, (w))
-
static __inline void
dc_initname(struct dircache *dc, char *name, u_int namelen)
{
@@ -334,7 +432,7 @@
}
static struct dircache *
-dc_alloc(struct dircache_mount *dm, enum dircache_type type,
+dc_alloc(struct dircache_ref *dr, enum dircache_type type,
char *name, u_int namelen)
{
struct dircache *dc;
@@ -342,7 +440,6 @@
dc = uma_zalloc(dircache_zone, M_WAITOK | M_ZERO);
DCDEBUG("alloc: %p %s\n", dc, name);
- dc->dc_mount = dm;
dc->dc_type = type;
refcount_init(&dc->dc_holdcnt, 1);
mtx_init(&dc->dc_mtx, "dircache entry", NULL, MTX_DEF | MTX_DUPOK);
@@ -350,6 +447,13 @@
if (name != NULL && namelen != 0)
dc_setname(dc, name, namelen, NULL);
+ dr_lock(dr);
+ dc_lock(dc);
+ dp_unused_insert(dc);
+ dr_add(dr, dc);
+ dc_unlock(dc);
+ dr_unlock(dr);
+
DC_STAT_INC(ds_alloc);
return (dc);
}
@@ -359,7 +463,7 @@
{
MPASS(RB_EMPTY(&dc->dc_children));
MPASS(dc->dc_parent == NULL);
- MPASS(dc->dc_vnode == NULL);
+ MPASS(dc->dc_ref == NULL);
DCDEBUG("free: %p %s\n", dc, dc->dc_name);
if (dc->dc_name != NULL)
@@ -379,6 +483,8 @@
static __inline int
dc_drop_int(struct dircache *dc, int islocked, int unlock)
{
+ struct dircache_ref *dr;
+
DCDEBUG("drop: %p usecnt=%d holdcnt=%d-1\n", dc, dc->dc_usecnt,
dc->dc_holdcnt);
if (refcount_release(&dc->dc_holdcnt) != 0) {
@@ -389,6 +495,12 @@
} else {
dc_assertlock(dc, MA_NOTOWNED);
}
+ dr = dc->dc_ref;
+ if (dr != NULL) {
+ dr_lock(dr);
+ dc->dc_ref = NULL;
+ dr_remove(dr, dc);
+ }
dc_free(dc);
return (1);
}
@@ -416,16 +528,14 @@
}
static struct dircache *
-dc_ref(struct dircache *dc)
+dc_use(struct dircache *dc)
{
MPASS(dc->dc_type != DT_INVALID);
dc_assertlock(dc, MA_OWNED);
dc_hold(dc);
- if (dc->dc_usecnt == 0) {
- MPASS(dc->dc_vnode == NULL);
+ if (dc->dc_usecnt == 0)
dp_unused_remove(dc);
- }
dc->dc_usecnt++;
DCDEBUG("ref: %p usecnt=%d holdcnt=%d\n", dc, dc->dc_usecnt,
dc->dc_holdcnt);
@@ -451,7 +561,6 @@
return (dropped);
}
- MPASS(dc->dc_vnode == NULL);
dp_unused_insert(dc);
dc_droplocked(dc);
@@ -464,11 +573,13 @@
return (dc_rele_int(dc, 1));
}
+#if 0
static int
dc_relesafe(struct dircache *dc)
{
return (dc_rele_int(dc, 0));
}
+#endif
static __inline void
dc_invalidate(struct dircache *dc)
@@ -491,160 +602,53 @@
}
}
-static void
-dc_refvnode(struct dircache *dc, struct vnode *vp)
-{
- if (dc->dc_type != DT_ROOT)
- dc_assertlock(dc, MA_OWNED);
- DCDEBUG("refvnode: %p %s; vp=%p; usecnt=%d\n", dc, dc->dc_name,
- vp, dc->dc_usecnt);
-
- MPASS(vp->v_type != VNON && vp->v_type != VBAD);
- MPASS(dc->dc_vnode == NULL);
- dc_ref(dc);
- dc->dc_vnode = vp;
- VI_LOCK(vp);
- if (vp->v_type == VDIR && !TAILQ_EMPTY(&vp->v_dircache))
- panic("dircache: multiple directory vnode references %p", vp);
- TAILQ_INSERT_HEAD(&vp->v_dircache, dc, dc_list);
- VI_UNLOCK(vp);
-}
-
-static void
-dc_relevnode(struct dircache *dc, int flags)
-{
- MPASS(dc->dc_vnode != NULL);
- dc_assertlock(dc, MA_OWNED);
- DCDEBUG("relevnode: %p %s; vp=%p; usecnt=%d\n", dc, dc->dc_name,
- dc->dc_vnode, dc->dc_usecnt);
-
- VI_LOCK(dc->dc_vnode);
- TAILQ_REMOVE(&dc->dc_vnode->v_dircache, dc, dc_list);
- if ((flags & DC_OP_VLOCK) == 0)
- VI_UNLOCK(dc->dc_vnode);
- dc->dc_vnode = NULL;
- dc_rele(dc);
-}
-
-static void
-dc_setinode(struct dircache *dc, ino_t inode)
-{
- struct dircache_mount *dm = dc->dc_mount;
-
- dc_assertlock(dc, MA_OWNED);
- MPASS(inode != 0);
- MPASS(dm != NULL);
- MPASS(dc->dc_inode == 0);
-
- dm_lock(dm);
- LIST_INSERT_HEAD(&dm->dm_inodehead, dc, dc_inodelist);
- dm_unlock(dm);
- dc->dc_inode = inode;
-}
-
-static void
-dc_zeroinode(struct dircache *dc)
-{
- struct dircache_mount *dm = dc->dc_mount;
-
- dc_assertlock(dc, MA_OWNED);
- MPASS(dm != NULL);
-
- if (dc->dc_inode == 0)
- return;
- dm_lock(dm);
- LIST_REMOVE(dc, dc_inodelist);
- dm_unlock(dm);
- dc->dc_inode = 0;
-}
-
-static int
-dc_vinterlock(struct vnode *vp, struct dircache *dc)
-{
- ASSERT_VI_LOCKED(vp, "dc_vinterlock");
- dc_assertlock(dc, MA_NOTOWNED);
-
- if (dc_trylock(dc)) {
- MPASS(dc->dc_vnode == vp);
- VI_UNLOCK(vp);
- return (0);
- }
-
- dc_hold(dc);
- VI_UNLOCK(vp);
- dc_lock(dc);
-
- if (dc->dc_vnode != vp) {
- VI_LOCK(vp);
- dc_droplocked(dc);
- goto restart;
- }
-
- if (dc_dropsafe(dc) != 0) {
- VI_LOCK(vp);
- goto restart;
- }
-
- MPASS(dc->dc_vnode == vp);
- return (0);
-
-restart:
- DC_STAT_INC(ds_vinterlock_restart);
- return (1);
-}
-
static struct dircache *
dc_getentry(struct vnode *vp, struct componentname *cnp, struct vnode *dvp)
{
+ struct dircache_ref *dr;
struct dircache *dc;
-restart:
- VI_LOCK(vp);
- dc = TAILQ_FIRST(&vp->v_dircache);
+ dr = dr_get(vp);
+ if (dr == NULL)
+ panic("dircache: reference to vnode disappeared: %.*s",
+ (int)cnp->cn_namelen, cnp->cn_nameptr);
+ dc = LIST_FIRST(&dr->dr_entries);
if (dc == NULL) {
- if ((vp->v_vflag & VV_ROOT) != 0) {
- dc = dm_get(vp)->dm_entry;
- VI_UNLOCK(vp);
- DCDEBUG("getentry: root %p vp=%p\n", dc, vp);
- MPASS(dc != NULL);
- dc_lock(dc);
- dc_refvnode(dc, vp);
- } else {
- VI_UNLOCK(vp);
+ dr_unlock(dr);
+ MPASS((vp->v_vflag & VV_ROOT) == 0);
#if 0
- DCDEBUG("getentry: not found vp=%p\n", vp);
+ DCDEBUG("getentry: not found vp=%p\n", vp);
#else
- panic("dircache: entry not found for vnode %p\n", vp);
+ panic("dircache: entry not found for vnode %p\n", vp);
#endif
- return (NULL);
- }
+ return (NULL);
} else {
- if (TAILQ_NEXT(dc, dc_list) != NULL) {
+ if (LIST_NEXT(dc, dc_reflist) != NULL) {
MPASS(cnp != NULL && dvp != NULL);
MPASS(vp->v_type != VDIR);
MPASS(!(cnp->cn_nameptr[0] == '.' &&
(cnp->cn_namelen == 1 || (cnp->cn_namelen == 2 &&
cnp->cn_nameptr[1] == '.'))));
- for(; dc != NULL; dc = TAILQ_NEXT(dc, dc_list)) {
- if (dc_vinterlock(vp, dc) != 0) {
- DCDEBUG("getenrty: restart; multiple entries; vp=%p\n",
- vp);
- goto restart;
+ for(; dc != NULL; dc = LIST_NEXT(dc, dc_reflist)) {
+ dc_lock(dc);
+ if (dc->dc_ref == NULL) {
+ dc_unlock(dc);
+ continue;
}
+ dr_unlock(dr);
dc_lock(dc->dc_parent);
if (dc_cmpname(dc, cnp->cn_nameptr,
cnp->cn_namelen) == 0 &&
- dvp == dc->dc_parent->dc_vnode) {
+ dvp->v_dircache == dc->dc_parent->dc_ref) {
dc_unlock(dc->dc_parent);
break;
}
dc_unlock(dc->dc_parent);
dc_unlock(dc);
- VI_LOCK(vp);
}
if (dc == NULL) {
- VI_UNLOCK(vp);
+ dr_unlock(dr);
#if 0
return (NULL);
#else
@@ -653,16 +657,13 @@
#endif
}
} else {
- if (dc_vinterlock(vp, dc) != 0) {
- DCDEBUG("getenrty: restart; node removed; vp=%p\n",
- vp);
- goto restart;
- }
+ dc_lock(dc);
+ dr_unlock(dr);
}
}
dc_assertlock(dc, MA_OWNED);
- MPASS(dc->dc_vnode == vp);
+ MPASS(dc->dc_ref->dr_vnode == vp);
return (dc);
}
@@ -730,63 +731,6 @@
return (dc);
}
-static struct dircache *
-dc_insert(struct dircache *pdc, struct dircache *dc,
- struct vnode *vp, ino_t inode)
-{
- struct dircache *col;
-
- DCDEBUG("insert: parent=%p name=%s\n", pdc, pdc->dc_name);
-
-restart:
- dc_assertlock(dc, MA_OWNED);
- dc_assertlock(pdc, MA_OWNED);
-
- col = RB_INSERT(dircache_tree, &pdc->dc_children, dc);
- if (col != NULL) {
- if (dc->dc_type == col->dc_type) {
- DCDEBUG("insert: warn: same entry added: %s\n",
- dc->dc_name);
- MPASS(col->dc_inode == inode);
- dc_unlock(pdc);
- dc_drop(dc);
- return (NULL);
- } else if (col->dc_type == DT_NEGATIVE) {
- DCDEBUG("insert: replace negative entry: %p %s\n",
- dc, dc->dc_name);
- dc_unlock(dc);
- if (dc_trylock(col) == 0) {
- dc_unlock(pdc);
- dc_lock(col);
- if (col->dc_parent != pdc) {
- dc_unlock(col);
- dc_lock(dc);
- dc_lock(pdc);
- DC_STAT_INC(ds_insert_restart);
- goto restart;
- }
- dc_lock(pdc);
- }
- col->dc_type = dc->dc_type;
- dc_setinode(col, inode);
- dc_unlock(pdc);
- dc_drop(dc);
- dc = col;
- } else
- panic("dircache: insert: ivalid entry: %d %s\n",
- dc->dc_type, dc->dc_name);
- } else {
- dp_unused_insert(dc);
- dc->dc_parent = pdc;
- dc_ref(pdc);
- dc_hold(dc);
- dc_unlock(pdc);
- }
- if (vp != NULL)
- dc_refvnode(dc, vp);
- return (dc);
-}
-
static __inline void
dc_assertempty(struct dircache *dc)
{
@@ -803,7 +747,7 @@
dc_removeentry(struct dircache *dc)
{
struct dircache *parent;
- int haschildren;
+ struct dircache_ref *dr;
MPASS(dc->dc_parent != NULL);
dc_assertlock(dc, MA_OWNED);
@@ -816,48 +760,62 @@
RB_REMOVE(dircache_tree, &parent->dc_children, dc);
if (dc->dc_type != DT_INVALID);
dc_invalidate(dc);
- dc_zeroinode(dc);
- haschildren = !RB_EMPTY(&dc->dc_children);
+
+ dr = dc->dc_ref;
+ dc->dc_ref = NULL;
+
dc_rele(parent);
- if (dc->dc_vnode != NULL) {
- dc_relevnode(dc, 0);
- if (haschildren != 0)
- dc_lock(dc);
- } else if (haschildren == 0)
+
+ if (!RB_EMPTY(&dc->dc_children)) {
+ dc_removechildren(dc);
+ } else
dc_unlock(dc);
- if (haschildren != 0)
- dc_removechildren(dc);
+
+ dr_lock(dr);
+ dr_remove(dr, dc);
+
dc_drop(dc);
}
static void
dc_marknegative(struct dircache *dc)
{
- int haschildren;
+ struct dircache_mount *dm;
+ struct dircache_ref *dr;
MPASS(dc->dc_parent != NULL);
dc_assertlock(dc, MA_OWNED);
dc_assertlock(dc->dc_parent, MA_OWNED);
dc_assertempty(dc);
- DCDEBUG("mark negative: %p %s; vp=%p\n", dc, dc->dc_name, dc->dc_vnode);
+ DCDEBUG("mark negative: %p %s; vp=%p\n",
+ dc, dc->dc_name, dc->dc_ref->dr_vnode);
dc_updategen(dc->dc_parent);
dc->dc_type = DT_NEGATIVE;
dc_unlock(dc->dc_parent);
- dc_zeroinode(dc);
- haschildren = !RB_EMPTY(&dc->dc_children);
- if (haschildren != 0)
- dc_hold(dc);
- if (dc->dc_vnode != NULL) {
- dc_relevnode(dc, 0);
- if (haschildren != 0)
- dc_lock(dc);
- } else if (haschildren == 0)
+
+ dr = dc->dc_ref;
+ dm = dr->dr_mount;
+ dc->dc_ref = NULL;
+
+ dc_hold(dc);
+
+ if (!RB_EMPTY(&dc->dc_children))
+ dc_removechildren(dc);
+ else
dc_unlock(dc);
- if (haschildren != 0) {
- dc_removechildren(dc);
- dc_drop(dc);
- }
+
+ dr_lock(dr);
+ dr_remove(dr, dc);
+
+ dr = dm->dm_negativeref;
+ dr_lock(dr);
+ dc_lock(dc);
+ dr_add(dr, dc);
+ dc_unlock(dc);
+ dr_unlock(dr);
+
+ dc_drop(dc);
}
static void
@@ -879,6 +837,58 @@
dc_unlock(dc);
}
+static struct dircache *
+dc_insertentry(struct dircache *pdc, struct dircache *dc)
+{
+ struct dircache *col;
+
+ DCDEBUG("insert: parent=%p name=%s\n", pdc, pdc->dc_name);
+
+restart:
+ dc_assertlock(dc, MA_OWNED);
+ dc_assertlock(pdc, MA_OWNED);
+
+ col = RB_INSERT(dircache_tree, &pdc->dc_children, dc);
+ if (col != NULL) {
+ if (dc->dc_type == col->dc_type) {
+ DCDEBUG("insert: warn: same entry added: %s\n",
+ dc->dc_name);
+ MPASS(col->dc_ref == dc->dc_ref);
+ dc_unlock(pdc);
+ dc_drop(dc);
+ return (NULL);
+ } else if (col->dc_type == DT_NEGATIVE) {
+ DCDEBUG("insert: replace negative entry: %p %s\n",
+ dc, dc->dc_name);
+ dc_unlock(dc);
+ if (dc_trylock(col) == 0) {
+ dc_unlock(pdc);
+ dc_lock(col);
+ if (col->dc_parent != pdc) {
+ dc_unlock(col);
+ dc_lock(dc);
+ dc_lock(pdc);
+ DC_STAT_INC(ds_insert_restart);
+ goto restart;
+ }
+ dc_lock(pdc);
+ }
+ dc_removeentry(col);
+ dc_lock(dc);
+ dc_lock(pdc);
+ goto restart;
+ } else
+ panic("dircache: insert: ivalid entry: %d %s\n",
+ dc->dc_type, dc->dc_name);
+ } else {
+ dc->dc_parent = pdc;
+ dc_use(pdc);
+ dc_hold(dc);
+ dc_unlock(pdc);
+ }
+ return (dc);
+}
+
static void
dp_unused_insert(struct dircache *dc)
{
@@ -976,7 +986,7 @@
if (dc_dropsafe(dc) == 0) {
dc_assertlock(dc, MA_OWNED);
dc_hold(dc);
- MPASS(dc->dc_vnode == NULL);
+ MPASS(dc->dc_ref->dr_vnode == NULL);
if (dc->dc_parent != NULL) {
dc_lock(dc->dc_parent);
dc_removeentry(dc);
@@ -1014,24 +1024,23 @@
void
dircache_init(struct mount *mp, ino_t inode)
{
+ struct dircache_mount *dm;
struct dircache *dc;
- struct dircache_mount *dm;
dm = malloc(sizeof(struct dircache_mount), M_DIRCACHE,
M_WAITOK | M_ZERO);
- mtx_init(&dm->dm_mtx, "dircache root", NULL, MTX_DEF);
- LIST_INIT(&dm->dm_inodehead);
+ mtx_init(&dm->dm_mtx, "dircache mount", NULL, MTX_DEF);
+ LIST_INIT(&dm->dm_inohead);
+ dm->dm_negativeref = dr_alloc(dm, NULL, 0);
+ dm->dm_rootref = dr_alloc(dm, NULL, inode);
MPASS(mp->mnt_dircache == NULL);
- dc = dc_alloc(dm, DT_ROOT, NULL, 0);
- dc_lock(dc);
- dp_unused_insert(dc);
- dc_setinode(dc, inode);
- dm->dm_entry = dc_ref(dc);
- dc_unlock(dc);
+ dc = dc_alloc(dm->dm_rootref, DT_ROOT, NULL, 0);
+
MNT_ILOCK(mp);
mp->mnt_dircache = dm;
MNT_IUNLOCK(mp);
+
DCDEBUG("init: root=%p %d\n", dc, inode);
}
@@ -1054,8 +1063,9 @@
MNT_IUNLOCK(mp);
restart:
- DCDEBUG("uninit: root=%p\n", dm->dm_entry);
- dc = dm->dm_entry;
+ dc = LIST_FIRST(&dm->dm_rootref->dr_entries);
+ MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
+ DCDEBUG("uninit: root=%p\n", dc);
dc_lock(dc);
while (dc != NULL && !RB_EMPTY(&dc->dc_children)) {
@@ -1094,7 +1104,8 @@
}
if (dc == NULL) {
- dc = dm->dm_entry;
+ dc = LIST_FIRST(&dm->dm_rootref->dr_entries);
+ MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
dc_lock(dc);
}
@@ -1108,13 +1119,14 @@
dp_invalid_clear();
mtx_unlock(&pool.dp_mtx);
- MPASS(LIST_EMPTY(&dm->dm_inodehead));
+ MPASS(LIST_EMPTY(&dm->dm_inohead));
free(dm, M_DIRCACHE);
}
void
dircache_purge_negative(struct vnode *vp)
{
+#if 0
TAILQ_HEAD(, dircache) head = TAILQ_HEAD_INITIALIZER(head);
struct dircache *dc, *child, *tmp;
int r;
@@ -1128,9 +1140,9 @@
}
if (vp->v_type == VDIR) {
MPASS(TAILQ_NEXT(dc, dc_list) == NULL);
- if (dc_vinterlock(vp, dc) != 0)
+ if (dc_refinterlock(vp, dc) != 0)
goto restart;
- dc_ref(dc);
+ 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,
@@ -1165,6 +1177,7 @@
}
VI_UNLOCK(vp);
}
+#endif
}
static int
@@ -1237,8 +1250,8 @@
error = ENOENT;
}
DC_STAT_INC(ds_hit_negative);
- } else if (dc->dc_vnode != NULL) {
- *vpp = dc->dc_vnode;
+ } else if (dc->dc_ref->dr_vnode != NULL) {
+ *vpp = dc->dc_ref->dr_vnode;
error = -1;
DC_STAT_INC(ds_hit);
} else {
@@ -1272,15 +1285,17 @@
int
dircache_add(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
- enum dircache_type type, ino_t inode)
+ enum dircache_type type)
{
struct dircache *pdc;
struct dircache *ndc;
MPASS(type == DT_STRONG || type == DT_WEAK);
+ MPASS(vp->v_dircache != NULL);
- DCDEBUG("add: inode=%d %s; vp=%p\n", inode, cnp->cn_nameptr, vp);
- ndc = dc_alloc(dm_get(dvp), type, cnp->cn_nameptr, cnp->cn_namelen);
+ DCDEBUG("add: %s; vp=%p\n", cnp->cn_nameptr, vp);
+ ndc = dc_alloc(vp->v_dircache, type,
+ cnp->cn_nameptr, cnp->cn_namelen);
dc_lock(ndc);
pdc = dc_getentry(dvp, NULL, NULL);
if (pdc == NULL) {
@@ -1288,7 +1303,7 @@
DC_STAT_INC(ds_add_error);
return (ENOENT);
}
- ndc = dc_insert(pdc, ndc, vp, inode);
+ ndc = dc_insertentry(pdc, ndc);
if (ndc != NULL) {
dc_updategen(ndc);
dc_unlock(ndc);
@@ -1298,6 +1313,32 @@
}
int
+dircache_addnegative(struct vnode *dvp, struct componentname *cnp)
+{
+ struct dircache *pdc;
+ struct dircache *ndc;
+
+ if (cnp->cn_nameptr[0] == '.' && (cnp->cn_namelen == 1 ||
+ (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.')))
+ panic("dircache: set negative for '.' or '..'");
+
+ ndc = dc_alloc(dm_get(dvp)->dm_negativeref, DT_NEGATIVE,
+ cnp->cn_nameptr, cnp->cn_namelen);
+ dc_lock(ndc);
+ pdc = dc_getentry(dvp, NULL, NULL);
+ if (pdc == NULL) {
+ dc_drop(ndc);
+ DC_STAT_INC(ds_setnegative_error);
+ return (ENOENT);
+ }
+ ndc = dc_insertentry(pdc, ndc);
+ if (ndc != NULL)
+ dc_unlock(ndc);
+ DC_STAT_INC(ds_setnegative);
+ return (0);
+}
+
+int
dircache_remove(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
{
struct dircache *dc;
@@ -1337,7 +1378,7 @@
if (dc != NULL) {
dc_lock(dc->dc_parent);
pdc = dc->dc_parent;
- dc_ref(pdc);
+ dc_use(pdc);
DCDEBUG("rename: remove target: %p %s; parent=%p\n",
dc, dc->dc_name, dc->dc_parent);
dc_updategen(dc->dc_parent);
@@ -1345,7 +1386,7 @@
} else {
pdc = dc_getentry(tdvp, NULL, NULL);
MPASS(pdc != NULL);
- dc_ref(pdc);
+ dc_use(pdc);
dc_unlock(pdc);
}
@@ -1421,72 +1462,48 @@
return (0);
}
-int
-dircache_setnegative(struct vnode *dvp, struct componentname *cnp)
+void
+dircache_allocvnode(struct vnode *vp, ino_t ino)
{
- struct dircache *pdc;
- struct dircache *ndc;
+ struct dircache *dc;
+ struct dircache_mount *dm;
+ struct dircache_ref *dr;
+
+ MPASS(vp->v_type != VNON && vp->v_type != VBAD);
+ MPASS(vp->v_dircache == NULL);
- if (cnp->cn_nameptr[0] == '.' && (cnp->cn_namelen == 1 ||
- (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.')))
- panic("dircache: set negative for '.' or '..'");
+ dm = dm_get(vp);
- ndc = dc_alloc(dm_get(dvp), DT_NEGATIVE, cnp->cn_nameptr,
- cnp->cn_namelen);
- dc_lock(ndc);
- pdc = dc_getentry(dvp, NULL, NULL);
- if (pdc == NULL) {
- dc_drop(ndc);
- DC_STAT_INC(ds_setnegative_error);
- return (ENOENT);
+ dm_lock(dm);
+ LIST_FOREACH(dr, &dm->dm_inohead, dr_inolist) {
+ if (dr->dr_ino == ino)
+ break;
}
- ndc = dc_insert(pdc, ndc, NULL, 0);
- if (ndc != NULL)
- dc_unlock(ndc);
- DC_STAT_INC(ds_setnegative);
- return (0);
-}
+ dm_unlock(dm);
+
+ if (dr == NULL)
+ dr = dr_alloc(dm_get(vp), vp, ino);
-int
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list