From owner-p4-projects@FreeBSD.ORG Mon Jul 19 22:27:02 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id DCE5D1065673; Mon, 19 Jul 2010 22:27:01 +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 A12CB106566C for ; Mon, 19 Jul 2010 22:27:01 +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 915708FC18 for ; Mon, 19 Jul 2010 22:27:01 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o6JMR1Jo023294 for ; Mon, 19 Jul 2010 22:27:01 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o6JMR1Yt023292 for perforce@freebsd.org; Mon, 19 Jul 2010 22:27:01 GMT (envelope-from gk@FreeBSD.org) Date: Mon, 19 Jul 2010 22:27:01 GMT Message-Id: <201007192227.o6JMR1Yt023292@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 181205 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: Mon, 19 Jul 2010 22:27:02 -0000 http://p4web.freebsd.org/@@181205?ac=10 Change 181205 by gk@gk_h1 on 2010/07/19 22:26:26 Cleanup dircache_ref refactoring Merge dircache_add and dicache_addnegative funcs Fix integer overflows in *_cmp() Affected files ... .. //depot/projects/soc2010/gk_namecache/sys/kern/subr_witness.c#3 edit .. //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#7 edit .. //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#7 edit Differences ... ==== //depot/projects/soc2010/gk_namecache/sys/kern/subr_witness.c#3 (text+ko) ==== @@ -614,16 +614,12 @@ { "vnode interlock", &lock_class_mtx_sleep }, { NULL, NULL }, /* - * dircache pool locks/vnode interlock + * dircache locks */ - { "dircache lock 0", &lock_class_mtx_sleep }, - { "dircache lock 1", &lock_class_mtx_sleep }, - { "dircache lock 2", &lock_class_mtx_sleep }, - { "dircache lock 3", &lock_class_mtx_sleep }, - { "dircache lock 4", &lock_class_mtx_sleep }, - { "dircache lock 5", &lock_class_mtx_sleep }, - { "dircache lock 6", &lock_class_mtx_sleep }, - { "dircache lock 7", &lock_class_mtx_sleep }, + { "dircache ref", &lock_class_mtx_sleep }, + { "dircache entry", &lock_class_mtx_sleep }, + { "dircache mount", &lock_class_mtx_sleep }, + { "dircache pool", &lock_class_mtx_sleep }, { "vnode interlock", &lock_class_mtx_sleep }, { NULL, NULL }, /* ==== //depot/projects/soc2010/gk_namecache/sys/kern/vfs_dircache.c#7 (text+ko) ==== @@ -80,9 +80,10 @@ struct dircache_mount { struct mtx dm_mtx; - LIST_HEAD(, dircache_ref) dm_inohead; + struct dircache_inotree dm_inohead; struct dircache_ref *dm_rootref; struct dircache_ref *dm_negativeref; + u_long dm_inocnt; }; static struct dircache * dc_use(struct dircache *dc); @@ -93,6 +94,8 @@ static void dp_unused_lazyclear(void); static void dp_invalid_lazyclear(void); +static int ds_mountstats(SYSCTL_HANDLER_ARGS); + static int dircache_debug = 1; static struct dircache_pool pool; static struct taskqueue *dc_tq; @@ -120,23 +123,24 @@ SYSCTL_ULONG(_vfs_dircache_stats, OID_AUTO, unused, CTLFLAG_RD, &pool.dp_unused_cnt, 0, "Unused entries"); +SYSCTL_PROC(_vfs_dircache_stats, OID_AUTO, inoderefs, + CTLFLAG_RD | CTLTYPE_ULONG | CTLFLAG_MPSAFE, NULL, + __offsetof(struct dircache_mount, dm_inocnt), ds_mountstats, "LU", ""); + enum { ds_hit, ds_hit_negative, ds_miss, ds_add, ds_add_error, + ds_add_negative, ds_remove, ds_remove_error, ds_rename, ds_rename_realloc, ds_rename_error, - ds_setnegative, - ds_setnegative_error, - ds_setvnode, - ds_setvnode_hit, - ds_setvnode_error, ds_allocvnode, + ds_allocvnode_inode_hit, ds_reclaimvnode, ds_alloc, ds_free, @@ -173,17 +177,14 @@ DC_STAT_DEFINE(miss, ""); DC_STAT_DEFINE(add, ""); DC_STAT_DEFINE(add_error, ""); +DC_STAT_DEFINE(add_negative, ""); DC_STAT_DEFINE(remove, ""); DC_STAT_DEFINE(remove_error, ""); DC_STAT_DEFINE(rename, ""); DC_STAT_DEFINE(rename_realloc, ""); DC_STAT_DEFINE(rename_error, ""); -DC_STAT_DEFINE(setnegative, ""); -DC_STAT_DEFINE(setnegative_error, ""); -DC_STAT_DEFINE(setvnode, ""); -DC_STAT_DEFINE(setvnode_hit, ""); -DC_STAT_DEFINE(setvnode_error, ""); DC_STAT_DEFINE(allocvnode, ""); +DC_STAT_DEFINE(allocvnode_inode_hit, ""); DC_STAT_DEFINE(reclaimvnode, ""); DC_STAT_DEFINE(alloc, ""); DC_STAT_DEFINE(free, ""); @@ -246,16 +247,52 @@ } SYSUNINIT(dircache, SI_SUB_VFS, SI_ORDER_SECOND, dircache_sysuninit, NULL); +static int +ds_mountstats(SYSCTL_HANDLER_ARGS) +{ + struct mount *mp; + char *ptr; + u_long res; + + if (arg2 < 0 || arg2 + sizeof(u_long) > sizeof(struct dircache_mount)) + return (EINVAL); + + res = 0; + mtx_lock(&mountlist_mtx); + TAILQ_FOREACH(mp, &mountlist, mnt_list) { + ptr = (char *)mp->mnt_dircache; + if (ptr == NULL) + continue; + + res += *(u_long *)(ptr + arg2); + } + mtx_unlock(&mountlist_mtx); + + return (SYSCTL_OUT(req, &res, sizeof(res))); +} + static __inline struct dircache_mount * dm_get(struct vnode *vp) { return (vp->v_mount->mnt_dircache); } +static __inline int +dr_cmp(struct dircache_ref *a, struct dircache_ref *b) +{ + if (a->dr_ino > b->dr_ino) + return (1); + else if (a->dr_ino < b->dr_ino) + return (-1); + return (0); +} + +RB_GENERATE_STATIC(dircache_inotree, dircache_ref, dr_inotree, dr_cmp); + static struct dircache_ref * dr_alloc(struct dircache_mount *dm, struct vnode *vp, ino_t ino) { - struct dircache_ref *dr; + 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); @@ -267,7 +304,9 @@ MPASS(dm_get(vp) == dr->dr_mount); if (ino != 0) { dm_lock(dm); - LIST_INSERT_HEAD(&dm->dm_inohead, dr, dr_inolist); + col = RB_INSERT(dircache_inotree, &dm->dm_inohead, dr); + dm->dm_inocnt++; + MPASS(col == NULL); dm_unlock(dm); } @@ -285,7 +324,8 @@ dr != dm->dm_rootref && dr != dm->dm_negativeref) { dr_unlock(dr); dm_lock(dm); - LIST_REMOVE(dr, dr_inolist); + RB_REMOVE(dircache_inotree, &dm->dm_inohead, dr); + dm->dm_inocnt--; dm_unlock(dm); uma_zfree(dircache_ref_zone, dr); } else @@ -350,7 +390,7 @@ r = dc->dc_namelen - namelen; if (r != 0) return (r); - r = bcmp(dc->dc_name, name, namelen); + r = memcmp(dc->dc_name, name, namelen); return (r); } @@ -365,7 +405,7 @@ r = a->dc_namelen - b->dc_namelen; if (r != 0) return (r); - r = bcmp(a->dc_name, b->dc_name, a->dc_namelen); + r = memcmp(a->dc_name, b->dc_name, a->dc_namelen); return (r); } @@ -376,7 +416,7 @@ { dc->dc_name = name; dc->dc_namelen = namelen; - dc->dc_namehash = hash32_buf(name, namelen, HASHINIT * namelen); + dc->dc_namehash = hash32_buf(name, namelen, HASHINIT * namelen) >> 1; } static __inline u_int @@ -432,8 +472,7 @@ } static struct dircache * -dc_alloc(struct dircache_ref *dr, enum dircache_type type, - char *name, u_int namelen) +dc_alloc(enum dircache_type type, char *name, u_int namelen) { struct dircache *dc; @@ -447,13 +486,6 @@ 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); } @@ -646,6 +678,7 @@ } dc_unlock(dc->dc_parent); dc_unlock(dc); + dr_lock(dr); } if (dc == NULL) { dr_unlock(dr); @@ -842,7 +875,8 @@ { struct dircache *col; - DCDEBUG("insert: parent=%p name=%s\n", pdc, pdc->dc_name); + DCDEBUG("insert: parent=%p name=%s dc=%p\n", + pdc, pdc->dc_name, dc); restart: dc_assertlock(dc, MA_OWNED); @@ -853,8 +887,13 @@ 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); + /* 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); + dc_unlock(dc); dc_drop(dc); return (NULL); } else if (col->dc_type == DT_NEGATIVE) { @@ -882,9 +921,12 @@ dc->dc_type, dc->dc_name); } else { dc->dc_parent = pdc; + dp_unused_insert(dc); dc_use(pdc); dc_hold(dc); dc_unlock(pdc); + dc_updategen(dc); + dc_unlock(dc); } return (dc); } @@ -931,7 +973,7 @@ DC_STAT_INC(ds_clearunused); dc = TAILQ_FIRST(&pool.dp_unused); while (dc != NULL && pool.dp_unused_cnt > pool.dp_unused_max) { - if (dc_trylock(dc) != 0) { + if (dc_trylock(dc) == 0) { dc = TAILQ_NEXT(dc, dc_list); shift++; if (shift >= pool.dp_unused_threshold) @@ -940,7 +982,7 @@ continue; } if (dc->dc_parent != NULL) { - if (dc_trylock(dc->dc_parent) != 0) { + if (dc_trylock(dc->dc_parent) == 0) { dc_unlock(dc); dc = TAILQ_NEXT(dc, dc_list); shift++; @@ -986,7 +1028,7 @@ if (dc_dropsafe(dc) == 0) { dc_assertlock(dc, MA_OWNED); dc_hold(dc); - MPASS(dc->dc_ref->dr_vnode == NULL); + MPASS(dc->dc_ref == NULL); if (dc->dc_parent != NULL) { dc_lock(dc->dc_parent); dc_removeentry(dc); @@ -1030,12 +1072,20 @@ dm = malloc(sizeof(struct dircache_mount), M_DIRCACHE, M_WAITOK | M_ZERO); mtx_init(&dm->dm_mtx, "dircache mount", NULL, MTX_DEF); - LIST_INIT(&dm->dm_inohead); + RB_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->dm_rootref, DT_ROOT, NULL, 0); + 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); MNT_ILOCK(mp); mp->mnt_dircache = dm; @@ -1119,7 +1169,14 @@ dp_invalid_clear(); mtx_unlock(&pool.dp_mtx); - MPASS(LIST_EMPTY(&dm->dm_inohead)); + dm_lock(dm); + RB_REMOVE(dircache_inotree, &dm->dm_inohead, dm->dm_rootref); + dm->dm_inocnt--; + dm_unlock(dm); + uma_zfree(dircache_ref_zone, dm->dm_rootref); + uma_zfree(dircache_ref_zone, dm->dm_negativeref); + + MPASS(RB_EMPTY(&dm->dm_inohead)); free(dm, M_DIRCACHE); } @@ -1289,52 +1346,37 @@ { struct dircache *pdc; struct dircache *ndc; + struct dircache_ref *dr; + + MPASS(type == DT_STRONG || type == DT_WEAK || type == DT_NEGATIVE); - MPASS(type == DT_STRONG || type == DT_WEAK); - MPASS(vp->v_dircache != NULL); + ndc = dc_alloc(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) { dc_drop(ndc); DC_STAT_INC(ds_add_error); return (ENOENT); } + dc_lock(ndc); ndc = dc_insertentry(pdc, ndc); if (ndc != NULL) { - dc_updategen(ndc); + if (type == DT_NEGATIVE) { + MPASS(vp == NULL); + dr = dm_get(dvp)->dm_negativeref; + dr_lock(dr); + } else { + dr = dr_get(vp); + } + MPASS(dr != NULL); + dc_lock(ndc); + dr_add(dr, ndc); dc_unlock(ndc); - } - DC_STAT_INC(ds_add); - return (0); -} + dr_unlock(dr); -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); + DC_STAT_INC(type == DT_NEGATIVE ? ds_add_negative : ds_add); return (0); } @@ -1467,22 +1509,23 @@ { struct dircache *dc; struct dircache_mount *dm; - struct dircache_ref *dr; + struct dircache_ref *dr, key; MPASS(vp->v_type != VNON && vp->v_type != VBAD); MPASS(vp->v_dircache == NULL); + MPASS(ino != 0); dm = dm_get(vp); dm_lock(dm); - LIST_FOREACH(dr, &dm->dm_inohead, dr_inolist) { - if (dr->dr_ino == ino) - break; - } + key.dr_ino = ino; + dr = RB_FIND(dircache_inotree, &dm->dm_inohead, &key); dm_unlock(dm); if (dr == NULL) dr = dr_alloc(dm_get(vp), vp, ino); + else + DC_STAT_INC(ds_allocvnode_inode_hit); DCDEBUG("alloc vnode: vp=%p; ino=%d; dr=%p\n", vp, ino, dr); ==== //depot/projects/soc2010/gk_namecache/sys/sys/dircache.h#7 (text+ko) ==== @@ -71,12 +71,14 @@ struct dircache_ref { struct mtx dr_mtx; LIST_HEAD(, dircache) dr_entries; - LIST_ENTRY(dircache_ref) dr_inolist; + RB_ENTRY(dircache_ref) dr_inotree; struct vnode *dr_vnode; struct dircache_mount *dr_mount; ino_t dr_ino; }; +RB_HEAD(dircache_inotree, dircache_ref); + void dircache_init(struct mount *mp, ino_t inode); void dircache_uninit(struct mount *mp); void dircache_purge_negative(struct vnode *dvp); @@ -85,7 +87,6 @@ struct componentname *cnp); int dircache_add(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, enum dircache_type type); -int dircache_addnegative(struct vnode *dvp, struct componentname *cnp); int dircache_remove(struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int dircache_rename(struct vnode *fdvp, struct componentname *fcnp, @@ -105,7 +106,7 @@ if (vp != NULL) error = dircache_add(dvp, vp, cnp, DT_STRONG); else - error = dircache_addnegative(dvp, cnp); + error = dircache_add(dvp, NULL, cnp, DT_NEGATIVE); return (error); }