From 91e37c7ac8f7fa8459efdd7f756d969332e3fb70 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 4 Mar 2011 12:47:30 +1100 Subject: [PATCH] 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 --- segments.c | 15 +++++++++------ state.h | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) 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 */ -- 2.39.5