Date: Fri, 20 Jun 2008 08:54:36 GMT From: Nick Barkas <snb@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 143807 for review Message-ID: <200806200854.m5K8saxf073994@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=143807 Change 143807 by snb@snb_toro on 2008/06/20 08:54:17 First cut at deleting a single dirhash whenever a vm_lowmem event occurs. Untested. Affected files ... .. //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#3 edit Differences ... ==== //depot/projects/soc2008/snb-dirhash/sys-ufs-ufs/ufs_dirhash.c#3 (text+ko) ==== @@ -89,7 +89,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(void); static int ufsdirhash_recycle(int wanted); +static void ufsdirhash_lowmem(void); static void ufsdirhash_free_locked(struct inode *ip); static uma_zone_t ufsdirhash_zone; @@ -1076,6 +1078,62 @@ } /* + * 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 + * -1 if unable to find any dirhashes that can be destroyed. + */ +static int +ufsdirhash_destroy() +{ + 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. */ + 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 = dh->dh_memreq; + dh->dh_memreq = 0; + + /* Unlock everything, free the detached memory. */ + ufsdirhash_release(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 (0); +} + +/* * Try to free up `wanted' bytes by stealing memory from existing * dirhashes. Returns zero with list locked if successful. */ @@ -1083,9 +1141,6 @@ ufsdirhash_recycle(int wanted) { struct dirhash *dh; - doff_t **hash; - u_int8_t *blkfree; - int i, mem, narrays; DIRHASHLIST_LOCK(); dh = TAILQ_FIRST(&ufsdirhash_list); @@ -1095,38 +1150,12 @@ DIRHASHLIST_UNLOCK(); 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; - } - 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 = dh->dh_memreq; - dh->dh_memreq = 0; + /* Try deleting a dirhash. Give up if we can't delete any. */ + if (ufsdirhash_destroy() < 0) + return (-1); - /* Unlock everything, free the detached memory. */ - ufsdirhash_release(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, and repeat if necessary. */ - DIRHASHLIST_LOCK(); - ufs_dirhashmem -= mem; + /* Repeat if necessary. */ dh = TAILQ_FIRST(&ufsdirhash_list); } /* Success; return with list locked. */ @@ -1139,7 +1168,16 @@ static void ufsdirhash_lowmem() { - + /* XXX: temporary silly way of notifying when this is called */ + printf("dirhash: ufsdirhash_lowmem() called\n"); + + DIRHASHLIST_LOCK(); + /* + * Try deleting only one dirhash for now, and don't bother + * to check if it worked. + */ + ufsdirhash_destroy(); + DIRHASHLIST_UNLOCK(); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200806200854.m5K8saxf073994>