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>