]> git.neil.brown.name Git - LaFS.git/commitdiff
Add AccountSpace reservation.
authorNeilBrown <neilb@suse.de>
Wed, 23 Jun 2010 05:55:47 +0000 (15:55 +1000)
committerNeilBrown <neilb@suse.de>
Fri, 25 Jun 2010 06:36:38 +0000 (16:36 +1000)
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 <neilb@suse.de>
modify.c
segments.c
state.h

index 8521291047194f0b009ce578db8ab62b6b6c65a2..481057d839e7f2bba0d9bf67875cf48ccee16bd3 100644 (file)
--- 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:
index ffed5c426864aa9ea779ea278ae6aaff3d33f422..18b76ad4a3e274d02d10d2dff91930d6475cf0b3 100644 (file)
@@ -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 e065060013ac5c890394a0534f47ae17bc05dc5e..35ee0b50251cde6f50cbf51349c5f9add38435be 100644 (file)
--- 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