diff options
author | snb <snb@FreeBSD.org> | 2009-06-17 18:55:29 +0000 |
---|---|---|
committer | snb <snb@FreeBSD.org> | 2009-06-17 18:55:29 +0000 |
commit | af1efe049038fd7911528165184d811f221f8513 (patch) | |
tree | a616f7247108a111e6bbaafa2b1b787090fa9e5c /sys/ufs | |
parent | 55cc3fe596da22b77d532e3c47fec3a5a67c3867 (diff) | |
download | FreeBSD-src-af1efe049038fd7911528165184d811f221f8513.zip FreeBSD-src-af1efe049038fd7911528165184d811f221f8513.tar.gz |
Keep dirhash tailq locked throughout the entirety of ufsdirhash_destroy() to fix
a potential race pointed out by pjd. Also use TAILQ_FOREACH_SAFE to iterate over
dirhashes in ufsdirhash_lowmem(), so that we can continue iterating even after a
dirhash is destroyed.
Suggested by: pjd
Tested by: pho
Approved by: dwmalone (mentor)
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ufs/ufs_dirhash.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c index 5066326..7f801af 100644 --- a/sys/ufs/ufs/ufs_dirhash.c +++ b/sys/ufs/ufs/ufs_dirhash.c @@ -1191,16 +1191,14 @@ ufsdirhash_destroy(struct dirhash *dh) mem = dh->dh_memreq; dh->dh_memreq = 0; - /* Unlock everything, free the detached memory. */ + /* Unlock dirhash and 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 (mem); @@ -1247,7 +1245,7 @@ ufsdirhash_recycle(int wanted) static void ufsdirhash_lowmem() { - struct dirhash *dh; + struct dirhash *dh, *dh_temp; int memfreed = 0; /* XXX: this 10% may need to be adjusted */ int memwanted = ufs_dirhashmem / 10; @@ -1259,8 +1257,7 @@ ufsdirhash_lowmem() * Delete dirhashes not used for more than ufs_dirhashreclaimage * 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)) { + TAILQ_FOREACH_SAFE(dh, &ufsdirhash_list, dh_list, dh_temp) { if (!sx_try_xlock(&dh->dh_lock)) continue; if (time_second - dh->dh_lastused > ufs_dirhashreclaimage) @@ -1275,11 +1272,14 @@ ufsdirhash_lowmem() * 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)) { - if (!sx_try_xlock(&dh->dh_lock)) - continue; - memfreed += ufsdirhash_destroy(dh); + if (memfreed < memwanted) { + TAILQ_FOREACH_SAFE(dh, &ufsdirhash_list, dh_list, dh_temp) { + if (!sx_try_xlock(&dh->dh_lock)) + continue; + memfreed += ufsdirhash_destroy(dh); + if (memfreed >= memwanted) + break; + } } DIRHASHLIST_UNLOCK(); } |