From owner-p4-projects@FreeBSD.ORG Thu Aug 14 13:26:42 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 446531065679; Thu, 14 Aug 2008 13:26:42 +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 086AC1065677 for ; Thu, 14 Aug 2008 13:26:42 +0000 (UTC) (envelope-from snb@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id E84418FC13 for ; Thu, 14 Aug 2008 13:26:41 +0000 (UTC) (envelope-from snb@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.2/8.14.2) with ESMTP id m7EDQffF084579 for ; Thu, 14 Aug 2008 13:26:41 GMT (envelope-from snb@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m7EDQfn8084577 for perforce@freebsd.org; Thu, 14 Aug 2008 13:26:41 GMT (envelope-from snb@FreeBSD.org) Date: Thu, 14 Aug 2008 13:26:41 GMT Message-Id: <200808141326.m7EDQfn8084577@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to snb@FreeBSD.org using -f From: Nick Barkas To: Perforce Change Reviews Cc: Subject: PERFORCE change 147376 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Aug 2008 13:26:42 -0000 http://perforce.freebsd.org/chv.cgi?CH=147376 Change 147376 by snb@snb_toro on 2008/08/14 13:26:35 Dynamic memory dirhash for FreeBSD 7 Affected files ... .. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/freebsd7/dirhash.h#2 edit .. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/freebsd7/ufs_dirhash.c#2 edit Differences ... ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/freebsd7/dirhash.h#2 (text+ko) ==== @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/ufs/ufs/dirhash.h,v 1.5 2005/01/07 02:29:26 imp Exp $ + * $FreeBSD$ */ #ifndef _UFS_UFS_DIRHASH_H_ @@ -100,6 +100,8 @@ int dh_onlist; /* true if on the ufsdirhash_list chain */ + time_t dh_lastused; /* time the dirhash was last read or written*/ + /* Protected by ufsdirhash_mtx. */ TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */ }; ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/freebsd7/ufs_dirhash.c#2 (text+ko) ==== @@ -28,7 +28,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/ufs/ufs/ufs_dirhash.c,v 1.23 2005/10/31 15:41:28 rwatson Exp $"); +__FBSDID("$FreeBSD$"); #include "opt_ufs.h" @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include @@ -79,6 +81,13 @@ static int ufs_dirhashcheck = 0; SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck, 0, "enable extra sanity tests"); +static int ufs_dirhashlowmemcount = 0; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD, + &ufs_dirhashlowmemcount, 0, "number of times low memory hook called"); +static int ufs_dirhashreclaimage = 5; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_reclaimage, CTLFLAG_RW, + &ufs_dirhashreclaimage, 0, + "max time in seconds of hash inactivity before deletion in low VM events"); static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen); @@ -87,7 +96,9 @@ static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen, doff_t offset); static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset); +static int ufsdirhash_destroy(struct dirhash *dh); static int ufsdirhash_recycle(int wanted); +static void ufsdirhash_lowmem(void); static uma_zone_t ufsdirhash_zone; @@ -215,6 +226,7 @@ dh->dh_seqopt = 0; dh->dh_seqoff = 0; dh->dh_score = DH_SCOREINIT; + dh->dh_lastused = time_second; ip->i_dirhash = dh; bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; @@ -377,6 +389,9 @@ if (dh->dh_score < DH_SCOREMAX) dh->dh_score++; + /* Update last used time. */ + dh->dh_lastused = time_second; + vp = ip->i_vnode; bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; blkoff = -1; @@ -643,6 +658,9 @@ dh->dh_hused++; DH_ENTRY(dh, slot) = offset; + /* Update last used time. */ + dh->dh_lastused = time_second; + /* Update the per-block summary info. */ ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp)); DIRHASH_UNLOCK(dh); @@ -1014,6 +1032,48 @@ } /* + * Delete the given dirhash and reclaim its memory. Assumes that + * ufsdirhash_list is locked, and leaves it locked. Also assumes + * that dh is locked. Returns the amount of memory freed. + */ +static int +ufsdirhash_destroy(struct dirhash *dh) +{ + doff_t **hash; + u_int8_t *blkfree; + int i, mem, narrays; + + KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list")); + + /* Remove it from the list and detach its memory. */ + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list); + dh->dh_onlist = 0; + hash = dh->dh_hash; + dh->dh_hash = NULL; + blkfree = dh->dh_blkfree; + dh->dh_blkfree = NULL; + narrays = dh->dh_narrays; + mem = narrays * sizeof(*dh->dh_hash) + + narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) + + dh->dh_nblk * sizeof(*dh->dh_blkfree); + + /* Unlock everything, free the detached memory. */ + DIRHASH_UNLOCK(dh); + DIRHASHLIST_UNLOCK(); + for (i = 0; i < narrays; i++) + DIRHASH_BLKFREE(hash[i]); + FREE(hash, M_DIRHASH); + FREE(blkfree, M_DIRHASH); + + /* Account for the returned memory. */ + DIRHASHLIST_LOCK(); + ufs_dirhashmem -= mem; + + return (mem); +} + + +/* * Try to free up `wanted' bytes by stealing memory from existing * dirhashes. Returns zero with list locked if successful. */ @@ -1021,9 +1081,6 @@ ufsdirhash_recycle(int wanted) { struct dirhash *dh; - doff_t **hash; - u_int8_t *blkfree; - int i, mem, narrays; DIRHASHLIST_LOCK(); while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) { @@ -1033,7 +1090,6 @@ return (-1); } DIRHASH_LOCK(dh); - KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list")); /* Decrement the score; only recycle if it becomes zero. */ if (--dh->dh_score > 0) { @@ -1042,32 +1098,50 @@ return (-1); } - /* Remove it from the list and detach its memory. */ - TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list); - dh->dh_onlist = 0; - hash = dh->dh_hash; - dh->dh_hash = NULL; - blkfree = dh->dh_blkfree; - dh->dh_blkfree = NULL; - narrays = dh->dh_narrays; - mem = narrays * sizeof(*dh->dh_hash) + - narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) + - dh->dh_nblk * sizeof(*dh->dh_blkfree); + /* Destroy the dirhash, and repeat if necessary. */ + ufsdirhash_destroy(dh); + } + /* Success; return with list locked. */ + return (0); +} + +/* + * Calback that frees some dirhashes when the system is low on virtual memory. + */ +static void +ufsdirhash_lowmem() +{ + struct dirhash *dh; + int memfreed = 0; + /* XXX: this 10% may need to be adjusted */ + int memwanted = ufs_dirhashmem / 10; - /* Unlock everything, free the detached memory. */ - DIRHASH_UNLOCK(dh); - DIRHASHLIST_UNLOCK(); - for (i = 0; i < narrays; i++) - DIRHASH_BLKFREE(hash[i]); - FREE(hash, M_DIRHASH); - FREE(blkfree, M_DIRHASH); + ufs_dirhashlowmemcount++; - /* Account for the returned memory, and repeat if necessary. */ - DIRHASHLIST_LOCK(); - ufs_dirhashmem -= mem; + DIRHASHLIST_LOCK(); + /* + * Delete dirhashes not used for more than ufs_dirhashreclaimage + * seconds. + */ + for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh = + TAILQ_NEXT(dh, dh_list)) { + if (time_second - dh->dh_lastused > ufs_dirhashreclaimage) { + DIRHASH_LOCK(dh); + memfreed += ufsdirhash_destroy(dh); + } + } + + /* + * If not enough memory was freed, keep deleting hashes from the head + * of the dirhash list. The ones closest to the head should be the + * oldest. + */ + for (dh = TAILQ_FIRST(&ufsdirhash_list); memfreed < memwanted && + dh !=NULL; dh = TAILQ_NEXT(dh, dh_list)) { + DIRHASH_LOCK(dh); + memfreed += ufsdirhash_destroy(dh); } - /* Success; return with list locked. */ - return (0); + DIRHASHLIST_UNLOCK(); } @@ -1078,6 +1152,11 @@ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF); TAILQ_INIT(&ufsdirhash_list); + + /* Register a callback function to handle low memory signals */ + EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL, + EVENTHANDLER_PRI_FIRST); + } void