From: NeilBrown Date: Wed, 23 Jun 2010 05:55:47 +0000 (+1000) Subject: Add AccountSpace reservation. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=b8361444a40bb2dd38afc57c0a6070e145f892a3;p=LaFS.git Add AccountSpace reservation. This is used when the space is needed for accounting space usage and so failure implies the filesystem is corrupt. Also start returning failure for ReserveSpace as we are gearing up to handle it Signed-off-by: NeilBrown --- diff --git a/modify.c b/modify.c index 8521291..481057d 100644 --- a/modify.c +++ b/modify.c @@ -1876,7 +1876,8 @@ int __must_check lafs_prealloc(struct block *blk, int why) int need; int credits = 0; - LAFS_BUG(why != CleanSpace && !test_phase_locked(fs) + LAFS_BUG(why != CleanSpace && why != AccountSpace + && !test_phase_locked(fs) && !fs->checkpointing, blk); retry: diff --git a/segments.c b/segments.c index ffed5c4..18b76ad 100644 --- a/segments.c +++ b/segments.c @@ -312,7 +312,7 @@ int lafs_seg_ref_block(struct block *b, int ssnum) continue; } - err = lafs_prealloc(&ss->ssblk->b, CleanSpace); + err = lafs_prealloc(&ss->ssblk->b, AccountSpace); if (err) { ss_put(ss, fs); putref(b, MKREF(segref)); @@ -377,7 +377,7 @@ void lafs_seg_move(struct fs *fs, u64 oldaddr, u64 newaddr, /* FIXME this doesn't belong here, does it ?*/ lafs_checkpoint_lock(fs); - (void)lafs_reserve_block(&ss->ssblk->b, CleanSpace); + (void)lafs_reserve_block(&ss->ssblk->b, AccountSpace); lafs_checkpoint_unlock(fs); if (!moveref) ss_put(ss, fs); @@ -591,6 +591,19 @@ void lafs_space_use(struct fs *fs, int credits) int lafs_space_alloc(struct fs *fs, int credits, int why) { + /* 'why's for space reservation. + * NewSpace means we want to write a block which didn't exist + * before. This is allowed to fail or block if the cleaner + * appears able to make progress. + * ReleaseSpace means we want to write a block which does currently + * exist, so doing this will eventually free up space. This must + * never fail, but can block. + * CleanSpace means we want to write a block to relocate it to + * a 'cleaning' segment. This may fail (e.g. if we need a checkpoint + * first to release from empty segments) but may not block. + * AccountSpace means we absolutely need this block now, and it is + * a BUG is there is no space available. + */ u64 watermark = 0; check_credits(fs); @@ -606,21 +619,34 @@ int lafs_space_alloc(struct fs *fs, int credits, int why) watermark += 3 * fs->max_segment; /* FALL THROUGH */ case CleanSpace: - /* no watermark for clean space? - * Maybe we need a few blocks for a checkpoint ? + /* Minimal watermark for clean space? + * Just need a few blocks for a checkpoint ? */ + watermark += 20; + /* FALL THROUGH */ + case AccountSpace: + /* Definitely no water mark here. */ break; } - if (why != ReleaseSpace) {/* FIXME currently don't handle - * EAGAIN, so never return it - */ - if (fs->rolled) { - if (fs->free_blocks < fs->allocated_blocks - + credits + watermark) - credits = 0; /* Sorry, no room */ - } + + if (fs->rolled) { + /* We cannot account properly before roll-forward has + * completed. FIXME once it has completed we need to + * check and invalidate the FS is there was a problem. + */ + if (fs->free_blocks < fs->allocated_blocks + + credits + watermark) + credits = 0; /* Sorry, no room */ } + + if (credits == 0 && why == AccountSpace) + /* FIXME I should switch to READ-ONLY here, + * not BUG. + */ + BUG(); + fs->allocated_blocks += credits; + BUG_ON(fs->free_blocks < fs->allocated_blocks); spin_unlock(&fs->alloc_lock); return credits; } @@ -1084,9 +1110,9 @@ void lafs_free_get(struct fs *fs, unsigned int *dev, u32 *seg, * to the two blocks !! */ LAFS_BUG(1, &db->b); lafs_checkpoint_lock(fs); - (void)lafs_reserve_block(&ssum->ssblk->b, CleanSpace); + (void)lafs_reserve_block(&ssum->ssblk->b, AccountSpace); if (ssnum == 0) - (void)lafs_reserve_block(&ssum->youthblk->b, CleanSpace); + (void)lafs_reserve_block(&ssum->youthblk->b, AccountSpace); lafs_dirty_dblock(db); lafs_checkpoint_unlock(fs); putdref(db, MKREF(youth)); @@ -1262,7 +1288,7 @@ static void clean_free(struct fs *fs) MKREF(cleanfree)); err = lafs_read_block(db); if (err == 0) - err = lafs_reserve_block(&db->b, CleanSpace); + err = lafs_reserve_block(&db->b, AccountSpace); if (err == 0) { u16 *b = map_dblock(db); spin_lock(&fs->stable_lock); @@ -1270,7 +1296,9 @@ static void clean_free(struct fs *fs) spin_unlock(&fs->stable_lock); unmap_dblock(db, b); lafs_dirty_dblock(db); - } + } else + /* FIXME make filesystem read-only */ + BUG(); putdref(db, MKREF(cleanfree)); } /* Now move them to the 'free' list */ diff --git a/state.h b/state.h index e065060..35ee0b5 100644 --- a/state.h +++ b/state.h @@ -136,6 +136,7 @@ struct fs { #define NewSpace 0 #define ReleaseSpace 1 #define CleanSpace 2 +#define AccountSpace 3 struct list_head inode_index; /* list of inode index_blocks, * largely so they can look hashed