]> git.neil.brown.name Git - LaFS.git/commitdiff
Add EmergencyClean mode
authorNeilBrown <neilb@suse.de>
Mon, 28 Jun 2010 10:27:44 +0000 (20:27 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 28 Jun 2010 22:22:55 +0000 (08:22 +1000)
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 <neilb@suse.de>
block.c
clean.c
segments.c
state.h

diff --git a/block.c b/block.c
index 1cfc4569cd7381a5a80fd043d749a189dff0673f..3304a95781ded09a27f0d4fe4b4e938930b97a86 100644 (file)
--- 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 885927bdcf0b16d1478931bffc27eee117d02880..dcf4b2026f2919399e8554ee4c609d2861f1c51a 100644 (file)
--- 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);
index 929b3b2fc8e17ab4c53744a35bf572407b44995f..8b59a48fcd4fb858de7e0f95c8c8d24f7094a0df 100644 (file)
@@ -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 085fc197264d60fc4b8391438144b387323a2457..96e634caacc1fe3bacd86c7c9064b4f5ff79606d 100644 (file)
--- 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 */