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