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));
/* 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);
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);
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;
}
* 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));
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);
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 */