]> git.neil.brown.name Git - LaFS.git/commitdiff
Allow for the possibilty of 'free_blocks' going negative.
authorNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 01:47:30 +0000 (12:47 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 01:47:30 +0000 (12:47 +1100)
While this shouldn't happen, the value of free_blocks isn't really
valid until the first segment scan completes.  If something gets
subtracted before that it could go negative temporarily.
We really want to handle that sort of situation gracefully.
So make it a 'signed' value.

Signed-off-by: NeilBrown <neilb@suse.de>
segments.c
state.h

index d422a8492d97354c7fd1e078dafe2be21f739270..aee53759160c5e507b4ddfaea40286bc376e9353 100644 (file)
@@ -661,9 +661,10 @@ int lafs_alloc_cleaner_segs(struct fs *fs, int max)
        int rv = 0;
        spin_lock(&fs->alloc_lock);
        while (fs->clean_reserved < max * fs->max_segment &&
-              fs->free_blocks > (fs->clean_reserved
-                                 + fs->allocated_blocks
-                                 + watermark)) {
+              fs->free_blocks > 0 &&
+              (u64)fs->free_blocks > (fs->clean_reserved
+                                      + fs->allocated_blocks
+                                      + watermark)) {
                fs->clean_reserved += fs->max_segment;
                fs->free_blocks -= fs->max_segment;
                rv++;
@@ -708,14 +709,16 @@ int lafs_space_alloc(struct fs *fs, int credits, int why)
                 * completed. FIXME once it has completed we need to
                 * check and invalidate the FS if there was a problem.
                 */
-               if (fs->free_blocks < fs->allocated_blocks
-                   + credits + watermark)
+               if (fs->free_blocks < 0 ||
+                   (u64)fs->free_blocks < (fs->allocated_blocks
+                                           + credits + watermark))
                        credits = 0; /* Sorry, no room */
        }
        if (fs->rolled && watermark == 0) {
                /* When including the clean_reserved space, there should
                 * be room for these controlled allocations
                 */
+               BUG_ON(fs->free_blocks < 0);
                if (fs->free_blocks + fs->clean_reserved <
                    fs->allocated_blocks + credits)
                        BUG();
@@ -1555,7 +1558,7 @@ void lafs_dump_cleanable(void)
                i++;
        }
        printk("--------\n");
-       printk("free_blocks=%llu allocated=%llu max_seg=%llu clean_reserved=%llu\n",
+       printk("free_blocks=%lld allocated=%llu max_seg=%llu clean_reserved=%llu\n",
               dfs->free_blocks, dfs->allocated_blocks, dfs->max_segment,
               dfs->clean_reserved);
 }
diff --git a/state.h b/state.h
index 0d373d827ff32104de70ae3e35f084eb262f5ed5..f65fb08562455106a20304f9672a556f27001896 100644 (file)
--- a/state.h
+++ b/state.h
@@ -170,7 +170,7 @@ struct fs {
 
        /* counters for (pre)allocating space. */
        spinlock_t alloc_lock;
-       u64     free_blocks; /* initialised from free segment info */
+       s64     free_blocks; /* initialised from free segment info */
        u64     allocated_blocks; /* Blocks that have been (pre)allocated */
        u64     clean_reserved; /* Blocks reserved for cleaner segments */
        u64     max_segment; /* largest segment size */