summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorsnb <snb@FreeBSD.org>2009-06-17 18:55:29 +0000
committersnb <snb@FreeBSD.org>2009-06-17 18:55:29 +0000
commitaf1efe049038fd7911528165184d811f221f8513 (patch)
treea616f7247108a111e6bbaafa2b1b787090fa9e5c /sys/ufs
parent55cc3fe596da22b77d532e3c47fec3a5a67c3867 (diff)
downloadFreeBSD-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.c22
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();
}
OpenPOWER on IntegriCloud