From: NeilBrown Date: Mon, 28 Jun 2010 10:27:44 +0000 (+1000) Subject: Add EmergencyClean mode X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=a27f30694715813e948ae716814c8e103dbe1362;p=LaFS.git Add EmergencyClean mode In this mode we are nearly full. Cleaning just goes for the segment with the most space even if it is quite new. Allocation failures return ENOSPC rather than EAGAIN We clean even if it doesn't look like it will help much. The heuristic for switching in an out is rather odd... Signed-off-by: NeilBrown --- diff --git a/block.c b/block.c index 1cfc456..3304a95 100644 --- a/block.c +++ b/block.c @@ -414,8 +414,11 @@ lafs_reserve_block(struct block *b, int alloc_type) if (err == 0) return 0; - if (alloc_type == NewSpace) - return -ENOSPC; + if (alloc_type == NewSpace) { + if (test_bit(EmergencyClean, &fs->fsstate)) + return -ENOSPC; + return -EAGAIN; + } if (alloc_type == ReleaseSpace) return -EAGAIN; LAFS_BUG(1, b); diff --git a/clean.c b/clean.c index 885927b..dcf4b20 100644 --- a/clean.c +++ b/clean.c @@ -616,6 +616,7 @@ static unsigned long do_clean(struct fs *fs) dprintk("C=%llu F=%llu T=%llu\n", C, F, T); if ((F < C || C * F >= T * (F - C)) && + !test_bit(EmergencyClean, &fs->fsstate) && !test_bit(CleanerBlocks, &fs->fsstate)) { dprintk("CLEANER: enough cleaning with %d segments\n", i); diff --git a/segments.c b/segments.c index 929b3b2..8b59a48 100644 --- a/segments.c +++ b/segments.c @@ -1477,6 +1477,13 @@ retry: spin_unlock(&fs->lock); segdelete(fs->segtrack, ss); + if (ss->usage < (fs->devs[ss->dev].segment_size - 4) * 126 / 128) + /* weird heuristic ?? */ + clear_bit(EmergencyClean, &fs->fsstate); + else if (ss->usage >= (fs->devs[ss->dev].segment_size - 4) * 127 / 128) + set_bit(EmergencyClean, &fs->fsstate); + + ssm = segsum_find(fs, ss->segment, ss->dev, 0); putdref(ssm->ssblk, MKREF(intable)); putdref(ssm->youthblk, MKREF(intable)); @@ -1512,7 +1519,10 @@ static int add_cleanable(struct fs *fs, unsigned int dev, u32 seg, return rv; } - score = youth * usage / segsize; + if (test_bit(EmergencyClean, &fs->fsstate)) + score = usage; + else + score = youth * usage / segsize + 0x10000; spin_lock(&fs->lock); diff --git a/state.h b/state.h index 085fc19..96e634c 100644 --- a/state.h +++ b/state.h @@ -93,6 +93,12 @@ struct fs { * cleaner to progress - cleaner.need blocks are * needed. */ +#define EmergencyClean 7/* Cleaner is in emergency mode and will clean + * the segment with the most space no matter + * how young it is. The fs is considered to + * be full and new allocation requests get + * -ENOSPC + */ struct work_struct done_work; /* used for handling * refile after write completes */