From: NeilBrown Date: Fri, 4 Mar 2011 01:47:30 +0000 (+1100) Subject: Allow for the possibilty of 'free_blocks' going negative. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=91e37c7ac8f7fa8459efdd7f756d969332e3fb70;p=LaFS.git Allow for the possibilty of 'free_blocks' going negative. 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 --- diff --git a/segments.c b/segments.c index d422a84..aee5375 100644 --- a/segments.c +++ b/segments.c @@ -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 0d373d8..f65fb08 100644 --- 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 */