Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=149041070deb2e83cd36dc60bc72975b3cbf5bbe
Commit:     149041070deb2e83cd36dc60bc72975b3cbf5bbe
Parent:     5b615287b37c32dc0c9dbeab13b19ac87828a5f7
Author:     Eric Sandeen <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 18:38:25 2007 -0400
Committer:  Theodore Ts'o <[EMAIL PROTECTED]>
CommitDate: Wed Oct 17 18:50:04 2007 -0400

    ext4: lighten up resize transaction requirements
    
    When resizing online, setup_new_group_blocks attempts to reserve a
    potentially very large transaction, depending on the current filesystem
    geometry.  For some journal sizes, there may not be enough room for this
    transaction, and the online resize will fail.
    
    The patch below resizes & restarts the transaction as necessary while
    setting up the new group, and should work with even the smallest journal.
    
    Tested with something like:
    
    [EMAIL PROTECTED] ~]# dd if=/dev/zero of=fsfile bs=1024 count=32768
    [EMAIL PROTECTED] ~]# mkfs.ext3 -b 1024 fsfile 16384
    [EMAIL PROTECTED] ~]# mount -o loop fsfile mnt/
    [EMAIL PROTECTED] ~]# resize2fs /dev/loop0
    resize2fs 1.40.2 (12-Jul-2007)
    Filesystem at /dev/loop0 is mounted on /root/mnt; on-line resizing required
    old desc_blocks = 1, new_desc_blocks = 1
    Performing an on-line resize of /dev/loop0 to 32768 (1k) blocks.
    resize2fs: No space left on device While trying to add group #2
    [EMAIL PROTECTED] ~]# dmesg | tail -n 1
    JBD: resize2fs wants too many credits (258 > 256)
    [EMAIL PROTECTED] ~]#
    
    With the below change, it works.
    
    Signed-off-by: Eric Sandeen <[EMAIL PROTECTED]>
    Signed-off-by: Mingming Cao <[EMAIL PROTECTED]>
    Acked-by: Andreas Dilger <[EMAIL PROTECTED]>
---
 fs/ext4/resize.c |   46 +++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 484e569..bd8a52b 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -141,6 +141,32 @@ static struct buffer_head *bclean(handle_t *handle, struct 
super_block *sb,
 }
 
 /*
+ * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA.
+ * If that fails, restart the transaction & regain write access for the
+ * buffer head which is used for block_bitmap modifications.
+ */
+static int extend_or_restart_transaction(handle_t *handle, int thresh,
+                                        struct buffer_head *bh)
+{
+       int err;
+
+       if (handle->h_buffer_credits >= thresh)
+               return 0;
+
+       err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);
+       if (err < 0)
+               return err;
+       if (err) {
+               if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
+                       return err;
+               if ((err = ext4_journal_get_write_access(handle, bh)))
+                       return err;
+        }
+
+       return 0;
+}
+
+/*
  * Set up the block and inode bitmaps, and the inode table for the new group.
  * This doesn't need to be part of the main transaction, since we are only
  * changing blocks outside the actual filesystem.  We still do journaling to
@@ -162,8 +188,9 @@ static int setup_new_group_blocks(struct super_block *sb,
        int i;
        int err = 0, err2;
 
-       handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks +
-                                      2 + sbi->s_itb_per_group);
+       /* This transaction may be extended/restarted along the way */
+       handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
+
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -190,6 +217,9 @@ static int setup_new_group_blocks(struct super_block *sb,
 
                ext4_debug("update backup group %#04lx (+%d)\n", block, bit);
 
+               if ((err = extend_or_restart_transaction(handle, 1, bh)))
+                       goto exit_bh;
+
                gdb = sb_getblk(sb, block);
                if (!gdb) {
                        err = -EIO;
@@ -215,6 +245,9 @@ static int setup_new_group_blocks(struct super_block *sb,
 
                ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit);
 
+               if ((err = extend_or_restart_transaction(handle, 1, bh)))
+                       goto exit_bh;
+
                if (IS_ERR(gdb = bclean(handle, sb, block))) {
                        err = PTR_ERR(bh);
                        goto exit_bh;
@@ -236,6 +269,10 @@ static int setup_new_group_blocks(struct super_block *sb,
                struct buffer_head *it;
 
                ext4_debug("clear inode block %#04lx (+%d)\n", block, bit);
+
+               if ((err = extend_or_restart_transaction(handle, 1, bh)))
+                       goto exit_bh;
+
                if (IS_ERR(it = bclean(handle, sb, block))) {
                        err = PTR_ERR(it);
                        goto exit_bh;
@@ -244,6 +281,10 @@ static int setup_new_group_blocks(struct super_block *sb,
                brelse(it);
                ext4_set_bit(bit, bh->b_data);
        }
+
+       if ((err = extend_or_restart_transaction(handle, 2, bh)))
+               goto exit_bh;
+
        mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
                        bh->b_data);
        ext4_journal_dirty_metadata(handle, bh);
@@ -271,7 +312,6 @@ exit_journal:
        return err;
 }
 
-
 /*
  * Iterate through the groups which hold BACKUP superblock/GDT copies in an
  * ext4 filesystem.  The counters should be initialized to 1, 5, and 7 before
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to