From owner-p4-projects@FreeBSD.ORG Sun Jul 6 21:16:24 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 469001065673; Sun, 6 Jul 2008 21:16:24 +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 0A4761065670 for ; Sun, 6 Jul 2008 21:16:24 +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 E96C58FC19 for ; Sun, 6 Jul 2008 21:16:23 +0000 (UTC) (envelope-from snb@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m66LGNL4094895 for ; Sun, 6 Jul 2008 21:16:23 GMT (envelope-from snb@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m66LGNde094893 for perforce@freebsd.org; Sun, 6 Jul 2008 21:16:23 GMT (envelope-from snb@FreeBSD.org) Date: Sun, 6 Jul 2008 21:16:23 GMT Message-Id: <200807062116.m66LGNde094893@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 144800 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: Sun, 06 Jul 2008 21:16:24 -0000 http://perforce.freebsd.org/chv.cgi?CH=144800 Change 144800 by snb@snb_toro on 2008/07/06 21:16:04 Upon receipt of vm_lowmem() signals, try deleting all dirhashes older than DH_RECLAIMAGE, set here to five seconds for now. If all the dirhashes are newer than this, just fall back to trying to delete the one at the beginning of ufsdirhash_list. DH_RECLAIMAGE probably will need tweaking, and so far dh_lastused is only being updated during calls to ufsdirhash_build(), ufsdirhash_lookup(), and ufsdirhash_add(). It may need to be updated when other functions are called as well. Also, I have not yet tested this code. This is a check point before I lose my network connection. Affected files ... .. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/dirhash.h#2 edit .. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#5 edit Differences ... ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/dirhash.h#2 (text+ko) ==== @@ -68,6 +68,12 @@ #define DH_SCOREINIT 8 /* initial dh_score when dirhash built */ #define DH_SCOREMAX 64 /* max dh_score value */ +/* + * If a vm_lowmem signal is received, we will try to free memory by + * deleting all hashes older than DH_RECLAIMAGE seconds. + */ +#define DH_RECLAIMAGE 5 + /* * The main hash table has 2 levels. It is an array of pointers to * blocks of DH_NBLKOFF offsets. @@ -101,6 +107,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/ufs_dirhash.c#5 (text+ko) ==== @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,8 @@ 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(void); +static int ufsdirhash_destroy(struct dirhash *dh); +static int ufsdirhash_destroy_first(void); static int ufsdirhash_recycle(int wanted); static void ufsdirhash_lowmem(void); static void ufsdirhash_free_locked(struct inode *ip); @@ -330,6 +332,7 @@ dh->dh_seqopt = 0; dh->dh_seqoff = 0; dh->dh_score = DH_SCOREINIT; + dh->dh_lastused = time_second; /* * Use non-blocking mallocs so that we will revert to a linear @@ -500,6 +503,9 @@ /* Update the score. */ if (dh->dh_score < DH_SCOREMAX) dh->dh_score++; + + /* Update last used time. */ + dh->dh_lastused = time_second; DIRHASHLIST_UNLOCK(); vp = ip->i_vnode; @@ -742,6 +748,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)); ufsdirhash_release(dh); @@ -1081,34 +1090,17 @@ } /* - * Delete the first dirhash on the list and reclaim its memory. - * Assumes that ufsdirhash_list is locked, and leaves it locked. - * If unable to obtain a lock on the first dirhash, moves down - * the list until it can lock a dirhash and destroys it. Returns - * the amount of memory freed, or -1 if unable to find any - * dirhashes that can be destroyed. + * 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() +ufsdirhash_destroy(struct dirhash *dh) { - struct dirhash *dh; doff_t **hash; u_int8_t *blkfree; int i, mem, narrays; - dh = TAILQ_FIRST(&ufsdirhash_list); - if (dh == NULL) - return (-1); - - /* - * If we can't lock it it's in use and we don't want to - * destroy it anyway. Go on to the next in the list. - */ - while (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { - dh = TAILQ_NEXT(dh, dh_list); - if (dh == NULL) - return (-1); - } KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list")); /* Remove it from the list and detach its memory. */ @@ -1132,7 +1124,7 @@ /* Account for the returned memory. */ DIRHASHLIST_LOCK(); - ufs_dirhashmem -= mem; + ufs_dirhashmem -= mem; return (mem); } @@ -1155,9 +1147,16 @@ return (-1); } - /* Try deleting a dirhash. Give up if we can't delete any. */ - if (ufsdirhash_destroy() < 0) - return (-1); + /* + * If we can't lock it it's in use and we don't want to + * recycle it anyway. + */ + if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { + dh = TAILQ_NEXT(dh, dh_list); + continue; + } + + ufsdirhash_destroy(dh); /* Repeat if necessary. */ dh = TAILQ_FIRST(&ufsdirhash_list); @@ -1172,15 +1171,35 @@ static void ufsdirhash_lowmem() { + struct dirhash *dh; + int memfreed = 0; + ufs_dirhashlowmemcount++; DIRHASHLIST_LOCK(); - if (ufs_dirhashmem > 0) - /* - * Try deleting only one dirhash for now, and don't bother - * to check if it worked. - */ - ufsdirhash_destroy(); + /* + * Delete all dirhashes not used for more than DH_RECLAIMAGE seconds. + * If we can't get a lock on the dirhash, it will be skipped. + */ + for (dh = TAILQ_FIRST(&ufsdirhash_list); dh != NULL; dh = + TAILQ_NEXT(dh, dh_list)) { + if (time_second - dh->dh_lastused > DH_RECLAIMAGE && + lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) + memfreed += ufsdirhash_destroy(dh); + } + + /* + * If no hashes were old enough, instead try deleting a single dirhash + * from the end of the list. + */ + dh = TAILQ_FIRST(&ufsdirhash_list); + while (memfreed == 0 && dh != NULL) { + if (lockmgr(&dh->dh_lock, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { + dh = TAILQ_NEXT(dh, dh_list); + continue; + } + memfreed += ufsdirhash_destroy(dh); + } DIRHASHLIST_UNLOCK(); }