Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Jul 2010 12:22:27 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 181047 for review
Message-ID:  <201007161222.o6GCMREi029515@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@181047?ac=10

Change 181047 by gk@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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007161222.o6GCMREi029515>