Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Jul 2010 08:21:36 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 181468 for review
Message-ID:  <201007280821.o6S8LZjr009150@repoman.freebsd.org>

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

Change 181468 by gk@gk_h1 on 2010/07/26 16:48:09

	Move children list head to dircache_ref to simplify forthcoming weak-only cache. Replace inode numbers with 64 bit ids (until ino_t remains 32 bit)

Affected files ...

.. //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_subr.c#6 edit
.. //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vfsops.c#4 edit
.. //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vnops.c#6 edit
.. //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#8 edit
.. //depot/projects/soc2010/gk_namecache/sys/modules/tmpfs/Makefile#4 edit
.. //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#8 edit

Differences ...

==== //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_subr.c#6 (text+ko) ====

@@ -401,7 +401,7 @@
 	error = insmntque(vp, mp);
 	if (error)
 		vp = NULL;
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	else
 		dircache_allocvnode(vp, node->tn_id);
 #endif
@@ -524,7 +524,7 @@
 	 * insert the new node into the directory, an operation that
 	 * cannot fail. */
 	tmpfs_dir_attach(dvp, de);
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_add(dvp, *vpp, cnp, DT_STRONG);
 #endif
 

==== //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vfsops.c#4 (text+ko) ====

@@ -247,6 +247,9 @@
 	MNT_ILOCK(mp);
 	mp->mnt_flag |= MNT_LOCAL;
 	mp->mnt_kern_flag |= MNTK_MPSAFE;
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
+	mp->mnt_kern_flag |= MNTK_DIRCACHE;
+#endif
 	MNT_IUNLOCK(mp);
 
 	mp->mnt_data = tmp;
@@ -254,8 +257,10 @@
 	vfs_getnewfsid(mp);
 	vfs_mountedfrom(mp, "tmpfs");
 
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_init(mp, root->tn_id);
+#elif defined(DIRCACHE_WEAK)
+	dircache_init(mp, 0);
 #endif
 
 	return 0;
@@ -327,7 +332,7 @@
 	mp->mnt_flag &= ~MNT_LOCAL;
 	MNT_IUNLOCK(mp);
 
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE)
 	dircache_uninit(mp);
 #endif
 

==== //depot/projects/soc2010/gk_namecache/sys/fs/tmpfs/tmpfs_vnops.c#6 (text+ko) ====

@@ -185,7 +185,10 @@
 	 * request was for creation, as it does not improve timings on
 	 * emprical tests. */
 	if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) {
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
+		dircache_add(dvp, *vpp, cnp,
+		    *vpp == NULL ? DT_NEGATIVE : DT_STRONG);
+#elif defined(DIRCACHE_WEAK)
 		dircache_enter(dvp, *vpp, cnp);
 #else
 		cache_enter(dvp, *vpp, cnp);
@@ -844,7 +847,7 @@
 	/* Remove the entry from the directory; as it is a file, we do not
 	 * have to change the number of hard links of the directory. */
 	tmpfs_dir_detach(dvp, de);
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_remove(dvp, vp, v->a_cnp);
 #endif
 
@@ -918,7 +921,7 @@
 
 	/* Insert the new directory entry into the appropriate directory. */
 	tmpfs_dir_attach(dvp, de);
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_add(dvp, vp, cnp, DT_STRONG);
 #endif
 
@@ -1145,7 +1148,7 @@
 		tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE);
 	}
 
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_rename(fdvp, fcnp, tdvp, tcnp);
 #endif
 
@@ -1243,7 +1246,7 @@
 
 	/* Detach the directory entry from the directory (dnode). */
 	tmpfs_dir_detach(dvp, de);
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE) && !defined(DIRCACHE_WEAK)
 	dircache_remove(dvp, vp, v->a_cnp);
 #endif
 
@@ -1264,8 +1267,13 @@
 	    TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
 	TMPFS_NODE_UNLOCK(dnode);
 
+#if defined(DIRCACHE_WEAK)
+	dircache_purge(dvp);
+	dircache_purge(vp);
+#elif defined(NO_DIRCACHE)
 	cache_purge(dvp);
 	cache_purge(vp);
+#endif
 
 	/* Free the directory entry we just deleted.  Note that the node
 	 * referred by it will not be removed until the vnode is really
@@ -1449,7 +1457,11 @@
 	tmp = VFS_TO_TMPFS(vp->v_mount);
 
 	vnode_destroy_vobject(vp);
+#if defined(DIRCACHE_WEAK)
+	dircache_purge(vp);
+#elif defined(NO_DIRCACHE)
 	cache_purge(vp);
+#endif
 
 	TMPFS_NODE_LOCK(node);
 	TMPFS_ASSERT_ELOCKED(node);
@@ -1468,7 +1480,7 @@
 
 	MPASS(vp->v_data == NULL);
 
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE)
 	dircache_reclaimvnode(vp);
 #endif
 
@@ -1576,7 +1588,7 @@
  */
 struct vop_vector tmpfs_vnodeop_entries = {
 	.vop_default =			&default_vnodeops,
-#ifndef NO_DIRCACHE
+#if !defined(NO_DIRCACHE)
 	.vop_lookup =			vfs_dircache_lookup,
 #else
 	.vop_lookup =			vfs_cache_lookup,

==== //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#8 (text+ko) ====

@@ -53,7 +53,7 @@
 
 #define	DC_NAMEROUND			32	/* power of 2 */
 
-#define	DC_OP_VLOCK			0x00000001
+#define	DC_OP_LOCKPREF			0x00000001
 
 #define DP_UNUSED_MIN			512
 #define DP_THRESHOLD_DFLT		256
@@ -64,6 +64,11 @@
 			printf(format ,## args);			\
 	} while (0)
 
+#define DC_ISTRONG(v)							\
+	((v)->v_mount->mnt_kern_flag & MNTK_DIRCACHE)
+#define DC_ASSERT_STRONG(v)		MPASS(DC_ISTRONG(v) != 0)
+#define DC_ASSERT_WEAK(v)		MPASS(DC_ISTRONG(v) == 0)
+
 struct dircache_pool {
 	struct mtx dp_mtx;
 	TAILQ_HEAD(, dircache) dp_unused;
@@ -80,10 +85,10 @@
 
 struct dircache_mount {
 	struct mtx dm_mtx;
-	struct dircache_inotree dm_inohead;
+	struct dircache_idtree dm_idhead;
 	struct dircache_ref *dm_rootref;
 	struct dircache_ref *dm_negativeref;
-	u_long dm_inocnt;
+	u_long dm_idcnt;
 };
 
 static struct dircache * dc_use(struct dircache *dc);
@@ -125,7 +130,7 @@
 
 SYSCTL_PROC(_vfs_dircache_stats, OID_AUTO, inoderefs,
     CTLFLAG_RD | CTLTYPE_ULONG | CTLFLAG_MPSAFE, NULL,
-    __offsetof(struct dircache_mount, dm_inocnt), ds_mountstats, "LU", "");
+    __offsetof(struct dircache_mount, dm_idcnt), ds_mountstats, "LU", "");
 
 enum {
 	ds_hit,
@@ -199,6 +204,7 @@
 
 #define dr_assertlock(dr, w)	mtx_assert(&(dr)->dr_mtx, (w))
 #define dr_lock(dr)		mtx_lock(&(dr)->dr_mtx)
+#define dr_trylock(dr)		mtx_trylock(&(dr)->dr_mtx)
 #define dr_unlock(dr)		mtx_unlock(&(dr)->dr_mtx)
 
 #define dc_lock(dc)		mtx_lock(&(dc)->dc_mtx)
@@ -280,32 +286,32 @@
 static __inline int
 dr_cmp(struct dircache_ref *a, struct dircache_ref *b)
 {
-	if (a->dr_ino > b->dr_ino)
+	if (a->dr_id > b->dr_id)
 		return (1);
-	else if (a->dr_ino < b->dr_ino)
+	else if (a->dr_id < b->dr_id)
 		return (-1);
 	return (0);
 }
 
-RB_GENERATE_STATIC(dircache_inotree, dircache_ref, dr_inotree, dr_cmp);
+RB_GENERATE_STATIC(dircache_idtree, dircache_ref, dr_idtree, dr_cmp);
 
 static struct dircache_ref *
-dr_alloc(struct dircache_mount *dm, struct vnode *vp, ino_t ino)
+dr_alloc(struct dircache_mount *dm, struct vnode *vp, uint64_t id)
 {
 	struct dircache_ref *dr, *col;
 
 	dr = uma_zalloc(dircache_ref_zone, M_WAITOK | M_ZERO);
-	mtx_init(&dr->dr_mtx, "dircache ref", NULL, MTX_DEF);
+	mtx_init(&dr->dr_mtx, "dircache ref", NULL, MTX_DEF | MTX_DUPOK);
 	LIST_INIT(&dr->dr_entries);
-	dr->dr_ino = ino;
+	dr->dr_id = id;
 	dr->dr_mount = dm;
 	dr->dr_vnode = vp;
 	if (vp != NULL)
 		MPASS(dm_get(vp) == dr->dr_mount);
-	if (ino != 0) {
+	if (id != 0) {
 		dm_lock(dm);
-		col = RB_INSERT(dircache_inotree, &dm->dm_inohead, dr);
-		dm->dm_inocnt++;
+		col = RB_INSERT(dircache_idtree, &dm->dm_idhead, dr);
+		dm->dm_idcnt++;
 		MPASS(col == NULL);
 		dm_unlock(dm);
 	}
@@ -322,10 +328,11 @@
 
 	if (dr->dr_vnode == NULL && LIST_EMPTY(&dr->dr_entries) &&
 	    dr != dm->dm_rootref && dr != dm->dm_negativeref) {
+		MPASS(RB_EMPTY(&dr->dr_children));
 		dr_unlock(dr);
 		dm_lock(dm);
-		RB_REMOVE(dircache_inotree, &dm->dm_inohead, dr);
-		dm->dm_inocnt--;
+		RB_REMOVE(dircache_idtree, &dm->dm_idhead, dr);
+		dm->dm_idcnt--;
 		dm_unlock(dm);
 		uma_zfree(dircache_ref_zone, dr);
 	} else
@@ -338,17 +345,29 @@
 {
 	struct dircache_ref *dr;
 
-restart:
 	dr = vp->v_dircache;
-	if (dr == NULL)
-		return (NULL);
+	MPASS(dr != NULL);
 	dr_lock(dr);
-	if (vp->v_dircache != dr) {
-		dr_unlock(dr);
-		goto restart;
-	}
+	MPASS(vp->v_dircache == dr);
+	return (dr);
+}
+
+static __inline struct dircache *
+dr_singleentry(struct dircache_ref *dr)
+{
+	struct dircache *dc;
+
+	dc = LIST_FIRST(&dr->dr_entries);
+	MPASS(dc != NULL);
+	MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
+
+	return (dc);
+}
 
-	return (dr);
+static __inline struct dircache_ref *
+dr_parentref(struct dircache_ref *dr)
+{
+	return (dr_singleentry(dr)->dc_parentref);
 }
 
 static void
@@ -356,8 +375,8 @@
 {
 	dr_assertlock(dr, MA_OWNED);
 
-	MPASS(dc->dc_ref == NULL);
-	dc->dc_ref = dr;
+	MPASS(dc->dc_selfref == NULL);
+	dc->dc_selfref = 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)
@@ -372,7 +391,7 @@
 static void
 dr_remove(struct dircache_ref *dr, struct dircache *dc)
 {
-	MPASS(dc->dc_ref == NULL);
+	MPASS(dc->dc_selfref == NULL);
 
 	LIST_REMOVE(dc, dc_reflist);
 	if (dr->dr_vnode != NULL) {
@@ -461,14 +480,13 @@
 }
 
 static __inline void
-dc_updategen(struct dircache *dc)
+dr_updategen(struct dircache_ref *dr)
 {
 	static u_long gen = 1;
 
-	dc_assertlock(dc, MA_OWNED);
 	do {
-		dc->dc_gen = atomic_fetchadd_long(&gen, 1);
-	} while (__predict_false(dc->dc_gen == 0));
+		dr->dr_gen = atomic_fetchadd_long(&gen, 1);
+	} while (__predict_false(dr->dr_gen == 0));
 }
 
 static struct dircache *
@@ -493,9 +511,8 @@
 static void
 dc_free(struct dircache *dc)
 {
-	MPASS(RB_EMPTY(&dc->dc_children));
-	MPASS(dc->dc_parent == NULL);
-	MPASS(dc->dc_ref == NULL);
+	MPASS(dc->dc_parentref == NULL);
+	MPASS(dc->dc_selfref == NULL);
 
 	DCDEBUG("free: %p %s\n", dc, dc->dc_name);
 	if (dc->dc_name != NULL)
@@ -527,10 +544,10 @@
 		} else {
 			dc_assertlock(dc, MA_NOTOWNED);
 		}
-		dr = dc->dc_ref;
+		dr = dc->dc_selfref;
 		if (dr != NULL) {
 			dr_lock(dr);
-			dc->dc_ref = NULL;
+			dc->dc_selfref = NULL;
 			dr_remove(dr, dc);
 		}
 		dc_free(dc);
@@ -575,8 +592,20 @@
 	return (dc);
 }
 
-static __inline int
-dc_rele_int(struct dircache *dc, int unlock)
+static void
+dc_use_byref(struct dircache_ref *dr)
+{
+	struct dircache *dc;
+
+	dr_assertlock(dr, MA_OWNED);
+	dc = dr_singleentry(dr);
+	dc_lock(dc);
+	dc_use(dc);
+	dc_unlock(dc);
+}
+
+static int
+dc_rele(struct dircache *dc)
 {
 	int dropped;
 
@@ -584,11 +613,11 @@
 
 	MPASS(dc->dc_usecnt > 0);
 	dc->dc_usecnt--;
-	DCDEBUG("rele: %p usecnt=%d holdcnt=%d-1 unlock=%d\n",
-	    dc, dc->dc_usecnt, dc->dc_holdcnt, unlock);
+	DCDEBUG("rele: %p usecnt=%d holdcnt=%d-1\n",
+	    dc, dc->dc_usecnt, dc->dc_holdcnt);
 
 	if (dc->dc_usecnt > 0) {
-		dropped = dc_drop_int(dc, 1, unlock);
+		dropped = dc_droplocked(dc);
 		MPASS(dropped == 0);
 		return (dropped);
 	}
@@ -600,18 +629,14 @@
 }
 
 static int
-dc_rele(struct dircache *dc)
+dc_rele_byref(struct dircache_ref *dr)
 {
-	return (dc_rele_int(dc, 1));
-}
+	struct dircache *dc;
 
-#if 0
-static int
-dc_relesafe(struct dircache *dc)
-{
-	return (dc_rele_int(dc, 0));
+	dc = dr_singleentry(dr);
+	dc_lock(dc);
+	return (dc_rele(dc));
 }
-#endif
 
 static __inline void
 dc_invalidate(struct dircache *dc)
@@ -635,15 +660,12 @@
 }
 
 static struct dircache *
-dc_getentry(struct vnode *vp, struct componentname *cnp, struct vnode *dvp)
+dc_getentry(struct vnode *vp, struct componentname *cnp, struct dircache_ref *parentref)
 {
 	struct dircache_ref *dr;
 	struct dircache *dc;
 
 	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) {
 		dr_unlock(dr);
@@ -656,7 +678,7 @@
 		return (NULL);
 	} else {
 		if (LIST_NEXT(dc, dc_reflist) != NULL) {
-			MPASS(cnp != NULL && dvp != NULL);
+			MPASS(cnp != NULL && parentref != NULL);
 			MPASS(vp->v_type != VDIR);
 			MPASS(!(cnp->cn_nameptr[0] == '.' &&
 			    (cnp->cn_namelen == 1 || (cnp->cn_namelen == 2 &&
@@ -664,21 +686,17 @@
 
 			for(; dc != NULL; dc = LIST_NEXT(dc, dc_reflist)) {
 				dc_lock(dc);
-				if (dc->dc_ref == NULL) {
+				if (dc->dc_selfref == 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->v_dircache == dc->dc_parent->dc_ref) {
-					dc_unlock(dc->dc_parent);
+				    parentref == dc->dc_parentref) {
+					dr_unlock(dr);
 					break;
 				}
-				dc_unlock(dc->dc_parent);
 				dc_unlock(dc);
-				dr_lock(dr);
 			}
 			if (dc == NULL) {
 				dr_unlock(dr);
@@ -696,71 +714,28 @@
 	}
 
 	dc_assertlock(dc, MA_OWNED);
-	MPASS(dc->dc_ref->dr_vnode == vp);
+	MPASS(dc->dc_selfref->dr_vnode == vp);
 	return (dc);
 }
 
-static int
-dc_parentinterlock(struct dircache *pdc, struct dircache *dc, int *pdcholdp)
-{
-	dc_assertlock(pdc, MA_OWNED);
-
-	if (dc_trylock(dc) != 0)
-		return (0);
-
-	if (pdcholdp != NULL && *pdcholdp == 0) {
-		dc_hold(pdc);
-		*pdcholdp += 1;
-	}
-
-	dc_hold(dc);
-	dc_unlock(pdc);
-	dc_lock(dc);
-	if (dc->dc_parent != pdc) {
-		dc_droplocked(dc);
-		dc_lock(pdc);
-		return (1);
-	}
-	if (dc_dropsafe(dc) != 0) {
-		dc_lock(pdc);
-		return (1);
-	}
-	dc_lock(pdc);
-	return (0);
-}
-
 static struct dircache *
-dc_find(struct vnode *dvp, struct componentname *cnp)
+dc_find(struct vnode *dvp, struct componentname *cnp, int flags)
 {
 	struct dircache key;
-	struct dircache *pdc, *dc;
-	int pdchold;
+	struct dircache_ref *parentref;
+	struct dircache *dc;
 
-	pdc = dc_getentry(dvp, NULL, NULL);
-	if (pdc == NULL)
-		return (NULL);
-	dc_assertlock(pdc, MA_OWNED);
-
-	pdchold = 0;
+	parentref = dr_get(dvp);
 	dc_initname(&key, cnp->cn_nameptr, cnp->cn_namelen);
 
-restart:
-	dc = RB_FIND(dircache_tree, &pdc->dc_children, &key);
-	if (dc == NULL) {
-		dc_unlock(pdc);
-		goto out;
-	}
-
-	if (dc_parentinterlock(pdc, dc, &pdchold) != 0) {
-		DC_STAT_INC(ds_lookup_restart);
-		goto restart;
-	}
-	dc_assertlock(dc, MA_OWNED);
-	dc_unlock(pdc);
+	dc = RB_FIND(dircache_tree, &parentref->dr_children, &key);
+	if (dc != NULL) {
+		dc_lock(dc);
+		if ((flags & DC_OP_LOCKPREF) == 0)
+			dr_unlock(parentref);
+	} else
+		dr_unlock(parentref);
 
-out:
-	if (pdchold != 0)
-		dc_drop(pdc);
 	return (dc);
 }
 
@@ -769,43 +744,43 @@
 {
 	struct dircache *child;
 
-	RB_FOREACH(child, dircache_tree, &dc->dc_children) {
+	RB_FOREACH(child, dircache_tree, &dc->dc_selfref->dr_children) {
 		MPASS(child->dc_type == DT_NEGATIVE);
 	}
 }
 
-static void dc_removechildren(struct dircache *dc);
+static void dr_removechildren(struct dircache_ref *ref);
 
 static void
-dc_removeentry(struct dircache *dc)
+dc_removeentry(struct dircache *dc, int flags)
 {
-	struct dircache *parent;
-	struct dircache_ref *dr;
+	struct dircache_ref *parentref;
+	struct dircache_ref *selfref;
 
-	MPASS(dc->dc_parent != NULL);
+	MPASS(dc->dc_parentref != NULL);
 	dc_assertlock(dc, MA_OWNED);
-	dc_assertlock(dc->dc_parent, MA_OWNED);
+	dr_assertlock(dc->dc_parentref, MA_OWNED);
 	dc_assertempty(dc);
 
 	DCDEBUG("remove entry: %p %s\n", dc, dc->dc_name);
-	parent = dc->dc_parent;
-	dc->dc_parent = NULL;
-	RB_REMOVE(dircache_tree, &parent->dc_children, dc);
+	parentref = dc->dc_parentref;
+	dc->dc_parentref = NULL;
+	RB_REMOVE(dircache_tree, &parentref->dr_children, dc);
 	if (dc->dc_type != DT_INVALID);
 		dc_invalidate(dc);
 
-	dr = dc->dc_ref;
-	dc->dc_ref = NULL;
+	selfref = dc->dc_selfref;
+	dc->dc_selfref = NULL;
 
-	dc_rele(parent);
+	dc_unlock(dc);
+	dr_lock(selfref);
 
-	if (!RB_EMPTY(&dc->dc_children)) {
-		dc_removechildren(dc);
-	} else
-		dc_unlock(dc);
-
-	dr_lock(dr);
-	dr_remove(dr, dc);
+	if (!RB_EMPTY(&selfref->dr_children))
+		dr_removechildren(selfref);
+	dr_remove(selfref, dc);
+	dc_rele_byref(parentref);
+	if ((flags & DC_OP_LOCKPREF) == 0)
+		dr_unlock(parentref);
 
 	dc_drop(dc);
 }
@@ -813,120 +788,104 @@
 static void
 dc_marknegative(struct dircache *dc)
 {
-	struct dircache_mount *dm;
-	struct dircache_ref *dr;
+	struct dircache_ref *selfref, *negativeref;
 
-	MPASS(dc->dc_parent != NULL);
+	MPASS(dc->dc_parentref != NULL);
 	dc_assertlock(dc, MA_OWNED);
-	dc_assertlock(dc->dc_parent, MA_OWNED);
+	dr_assertlock(dc->dc_parentref, MA_OWNED);
 	dc_assertempty(dc);
 
 	DCDEBUG("mark negative: %p %s; vp=%p\n",
-	    dc, dc->dc_name, dc->dc_ref->dr_vnode);
-	dc_updategen(dc->dc_parent);
+	    dc, dc->dc_name, dc->dc_selfref->dr_vnode);
+	dr_updategen(dc->dc_parentref);
 	dc->dc_type = DT_NEGATIVE;
-	dc_unlock(dc->dc_parent);
 
-	dr = dc->dc_ref;
-	dm = dr->dr_mount;
-	dc->dc_ref = NULL;
+	selfref = dc->dc_selfref;
+	negativeref = selfref->dr_mount->dm_negativeref;
+	dc->dc_selfref = NULL;
 
 	dc_hold(dc);
+	dc_unlock(dc);
+	dr_lock(selfref);
 
-	if (!RB_EMPTY(&dc->dc_children))
-		dc_removechildren(dc);
-	else
-		dc_unlock(dc);
+	dr_removechildren(selfref);
+	dr_remove(selfref, dc);
 
-	dr_lock(dr);
-	dr_remove(dr, dc);
-
-	dr = dm->dm_negativeref;
-	dr_lock(dr);
+	dr_lock(negativeref);
+	dr_unlock(dc->dc_parentref);
 	dc_lock(dc);
-	dr_add(dr, dc);
+	dr_add(negativeref, dc);
 	dc_unlock(dc);
-	dr_unlock(dr);
+	dr_unlock(negativeref);
 
 	dc_drop(dc);
 }
 
 static void
-dc_removechildren(struct dircache *dc)
+dr_removechildren(struct dircache_ref *ref)
 {
 	struct dircache *child;
 
-	dc_assertlock(dc, MA_OWNED);
+	dr_assertlock(ref, MA_OWNED);
 
-	DCDEBUG("remove children: %p %s\n", dc, dc->dc_name);
-	while(!RB_EMPTY(&dc->dc_children)) {
-		child = RB_MIN(dircache_tree, &dc->dc_children);
-		if (dc_parentinterlock(dc, child, NULL) != 0)
-			continue;
-		MPASS(RB_EMPTY(&child->dc_children));
-		dc_removeentry(child);
-		dc_lock(dc);
+	DCDEBUG("remove children: ref=%p\n", ref);
+	while(!RB_EMPTY(&ref->dr_children)) {
+		child = RB_MIN(dircache_tree, &ref->dr_children);
+		dc_lock(child);
+		MPASS(RB_EMPTY(&child->dc_selfref->dr_children));
+		dc_removeentry(child, DC_OP_LOCKPREF);
 	}
-	dc_unlock(dc);
+
+	dr_assertlock(ref, MA_OWNED);
 }
 
 static struct dircache *
-dc_insertentry(struct dircache *pdc, struct dircache *dc)
+dc_insertentry(struct dircache_ref *parentref, struct dircache *dc)
 {
 	struct dircache *col;
 
-	DCDEBUG("insert: parent=%p name=%s dc=%p\n",
-	    pdc, pdc->dc_name, dc);
+	DCDEBUG("insert: parent=%p dc=%p\n",
+	    parentref, dc);
 
 restart:
+	dr_assertlock(parentref, MA_OWNED);
 	dc_assertlock(dc, MA_OWNED);
-	dc_assertlock(pdc, MA_OWNED);
 
-	col = RB_INSERT(dircache_tree, &pdc->dc_children, dc);
+	col = RB_INSERT(dircache_tree, &parentref->dr_children, dc);
 	if (col != NULL) {
 		if (dc->dc_type == col->dc_type) {
 			DCDEBUG("insert: warn: same entry added: %s\n",
 			    dc->dc_name);
-			/* TODO
-			KASSERT(col->dc_ref == dr,
-			    ("dircache: entry already exists: %s %p %p\n",
-			    dc->dc_name, col->dc_ref, dc->dc_ref));
-			*/
-			dc_unlock(pdc);
+			dr_unlock(parentref);
 			dc_unlock(dc);
 			dc_drop(dc);
-			return (NULL);
+			return (col);
 		} 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_lock(col);
+			if (col->dc_parentref != parentref) {
+				dc_unlock(col);
+				dc_lock(dc);
+				dr_assertlock(parentref, MA_OWNED);
+				DC_STAT_INC(ds_insert_restart);
+				goto restart;
 			}
-			dc_removeentry(col);
+			dc_removeentry(col, DC_OP_LOCKPREF);
 			dc_lock(dc);
-			dc_lock(pdc);
+			dr_assertlock(parentref, MA_OWNED);
 			goto restart;
 		} else
 			panic("dircache: insert: ivalid entry: %d %s\n",
 			    dc->dc_type, dc->dc_name);
 	} else {
-		dc->dc_parent = pdc;
+		dc->dc_parentref = parentref;
 		dp_unused_insert(dc);
-		dc_use(pdc);
+		dc_use_byref(parentref);
 		dc_hold(dc);
-		dc_unlock(pdc);
-		dc_updategen(dc);
 		dc_unlock(dc);
+		dr_unlock(parentref);
 	}
 	return (dc);
 }
@@ -981,8 +940,8 @@
 			DC_STAT_INC(ds_clearunused_restart);
 			continue;
 		}
-		if (dc->dc_parent != NULL) {
-			if (dc_trylock(dc->dc_parent) == 0) {
+		if (dc->dc_parentref != NULL) {
+			if (dr_trylock(dc->dc_parentref) == 0) {
 				dc_unlock(dc);
 				dc = TAILQ_NEXT(dc, dc_list);
 				shift++;
@@ -993,8 +952,8 @@
 			}
 		}
 		mtx_unlock(&pool.dp_mtx);
-		MPASS(RB_EMPTY(&dc->dc_children));
-		dc_removeentry(dc);
+		MPASS(RB_EMPTY(&dc->dc_selfref->dr_children));
+		dc_removeentry(dc, 0);
 		mtx_lock(&pool.dp_mtx);
 		dc = TAILQ_FIRST(&pool.dp_unused);
 		shift = 0;
@@ -1015,6 +974,7 @@
 dp_invalid_clear(void)
 {
 	struct dircache *dc;
+	struct dircache_ref *parentref;
 
 	mtx_assert(&pool.dp_mtx, MA_OWNED);
 
@@ -1027,15 +987,23 @@
 		dc_lock(dc);
 		if (dc_dropsafe(dc) == 0) {
 			dc_assertlock(dc, MA_OWNED);
-			dc_hold(dc);
-			MPASS(dc->dc_ref == NULL);
-			if (dc->dc_parent != NULL) {
-				dc_lock(dc->dc_parent);
-				dc_removeentry(dc);
+			MPASS(dc->dc_selfref == NULL);
+			parentref = dc->dc_parentref;
+			if (parentref != NULL) {
+				dc_hold(dc);
+				dc_unlock(dc);
+				dr_lock(parentref);
 				dc_lock(dc);
+				if (dc->dc_parentref != parentref) {
+					dr_unlock(parentref);
+					dc_unlock(dc);
+					mtx_lock(&pool.dp_mtx);
+					continue;
+				}
+				dc_removeentry(dc, 0);
+				dc_drop(dc);
 			} else
-				dc_removechildren(dc);
-			dc_drop(dc);
+				dc_unlock(dc);
 		}
 		mtx_lock(&pool.dp_mtx);
 	}
@@ -1064,7 +1032,7 @@
 }
 
 void
-dircache_init(struct mount *mp, ino_t inode)
+dircache_init(struct mount *mp, uint64_t id)
 {
 	struct dircache_mount *dm;
 	struct dircache *dc;
@@ -1072,34 +1040,40 @@
 	dm = malloc(sizeof(struct dircache_mount), M_DIRCACHE,
 	    M_WAITOK | M_ZERO);
 	mtx_init(&dm->dm_mtx, "dircache mount", NULL, MTX_DEF);
-	RB_INIT(&dm->dm_inohead);
+	RB_INIT(&dm->dm_idhead);
 	dm->dm_negativeref = dr_alloc(dm, NULL, 0);
-	dm->dm_rootref = dr_alloc(dm, NULL, inode);
+	if (id != 0) {
+		MPASS((mp->mnt_kern_flag & MNTK_DIRCACHE) != 0);
+		dm->dm_rootref = dr_alloc(dm, NULL, id);
 
-	MPASS(mp->mnt_dircache == NULL);
-	dc = dc_alloc(DT_ROOT, NULL, 0);
+		MPASS(mp->mnt_dircache == NULL);
+		dc = dc_alloc(DT_ROOT, NULL, 0);
 
-	dr_lock(dm->dm_rootref);
-	dc_lock(dc);
-	dp_unused_insert(dc);
-	dr_add(dm->dm_rootref, dc);
-	dc_use(dc);
-	dc_unlock(dc);
-	dr_unlock(dm->dm_rootref);
+		dr_lock(dm->dm_rootref);
+		dc_lock(dc);
+		dp_unused_insert(dc);
+		dr_add(dm->dm_rootref, dc);
+		dc_use(dc);
+		dc_unlock(dc);
+		dr_unlock(dm->dm_rootref);
+		DCDEBUG("init: root=%p %jd\n", dc, (intmax_t)id);
+	} else {
+		MPASS((mp->mnt_kern_flag & MNTK_DIRCACHE) == 0);
+		DCDEBUG("init: weak\n");
+	}
 
 	MNT_ILOCK(mp);
 	mp->mnt_dircache = dm;
 	MNT_IUNLOCK(mp);
-
-	DCDEBUG("init: root=%p %d\n", dc, inode);
 }
 
 void
 dircache_uninit(struct mount *mp)
 {
+	struct dircache_ref *dr, *childref;
 	struct dircache *dc, *child;
 	struct dircache_mount *dm;
-	int dropped, dchold;
+	int dropped;
 
 	MPASS(mp->mnt_dircache != NULL);
 
@@ -1113,54 +1087,49 @@
 	MNT_IUNLOCK(mp);
 
 restart:
-	dc = LIST_FIRST(&dm->dm_rootref->dr_entries);
-	MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
-	DCDEBUG("uninit: root=%p\n", dc);
-	dc_lock(dc);
+	dr = dm->dm_rootref;
+	dr_lock(dr);
+	DCDEBUG("uninit: rootref=%p\n", dr);
 
-	while (dc != NULL && !RB_EMPTY(&dc->dc_children)) {
+	while (dr != NULL && !RB_EMPTY(&dr->dr_children)) {
 nested:
-		dc_assertlock(dc, MA_OWNED);
-		RB_FOREACH(child, dircache_tree, &dc->dc_children) {
-			if (!RB_EMPTY(&child->dc_children)) {
-				dchold = 0;
-				dropped = dc_parentinterlock(dc, child,
-				    &dchold);
-				if (dchold != 0)
-					dc_droplocked(dc);
-				else
-					dc_unlock(dc);
-				if (dropped != 0)
-					goto restart;
-				dc = child;
-				DCDEBUG("uninit: go down: %p %s\n",
-				    dc, dc->dc_name);
+		dr_assertlock(dr, MA_OWNED);
+		RB_FOREACH(child, dircache_tree, &dr->dr_children) {
+			childref = child->dc_selfref;
+			dr_lock(childref);
+			if (!RB_EMPTY(&childref->dr_children)) {
+				dr_unlock(dr);
+				dr = childref;
+				DCDEBUG("uninit: go down: ref=%p %s\n",
+				    childref, child->dc_name);
 				goto nested;
 			}
+			dr_unlock(childref);
 		}
-		child = dc;
-		dc = dc->dc_parent;
-		if (dc != NULL)
-			dc_hold(dc);
-		dc_hold(child);
-		dc_removechildren(child);
-		dc_drop(child);
-		if (dc != NULL) {
-			dc_lock(dc);
-			if (dc_dropsafe(dc) != 0)
+		childref = dr;
+		dr = dr_parentref(dr);
+		dr_removechildren(childref);
+		if (dr != NULL) {
+			if (dr_trylock(dr) == 0)  {
+				dr_unlock(childref);
 				goto restart;
-			DCDEBUG("uninit: go up: %p %s\n", dc, dc->dc_name);
-		}
+			}
+			dr_unlock(childref);
+			DCDEBUG("uninit: go up: ref=%p\n", dr);
+		} else
+			dr_unlock(childref);
 	}
 
-	if (dc == NULL) {
-		dc = LIST_FIRST(&dm->dm_rootref->dr_entries);
-		MPASS(LIST_NEXT(dc, dc_reflist) == NULL);
-		dc_lock(dc);

>>> TRUNCATED FOR MAIL (1000 lines) <<<



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