Commit 14904107 authored by Eric Sandeen's avatar Eric Sandeen Committed by Theodore Ts'o

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:

[root@newbox ~]# dd if=/dev/zero of=fsfile bs=1024 count=32768
[root@newbox ~]# mkfs.ext3 -b 1024 fsfile 16384
[root@newbox ~]# mount -o loop fsfile mnt/
[root@newbox ~]# 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
[root@newbox ~]# dmesg | tail -n 1
JBD: resize2fs wants too many credits (258 > 256)
[root@newbox ~]#

With the below change, it works.
Signed-off-by: default avatarEric Sandeen <sandeen@redhat.com>
Signed-off-by: default avatarMingming Cao <cmm@us.ibm.com>
Acked-by: default avatarAndreas Dilger <adilger@clusterfs.com>
parent 5b615287
...@@ -140,6 +140,32 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, ...@@ -140,6 +140,32 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
return bh; return bh;
} }
/*
* 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. * 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 * This doesn't need to be part of the main transaction, since we are only
...@@ -162,8 +188,9 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -162,8 +188,9 @@ static int setup_new_group_blocks(struct super_block *sb,
int i; int i;
int err = 0, err2; int err = 0, err2;
handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks + /* This transaction may be extended/restarted along the way */
2 + sbi->s_itb_per_group); handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
...@@ -190,6 +217,9 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -190,6 +217,9 @@ static int setup_new_group_blocks(struct super_block *sb,
ext4_debug("update backup group %#04lx (+%d)\n", block, bit); 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); gdb = sb_getblk(sb, block);
if (!gdb) { if (!gdb) {
err = -EIO; err = -EIO;
...@@ -215,6 +245,9 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -215,6 +245,9 @@ static int setup_new_group_blocks(struct super_block *sb,
ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit); 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))) { if (IS_ERR(gdb = bclean(handle, sb, block))) {
err = PTR_ERR(bh); err = PTR_ERR(bh);
goto exit_bh; goto exit_bh;
...@@ -236,6 +269,10 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -236,6 +269,10 @@ static int setup_new_group_blocks(struct super_block *sb,
struct buffer_head *it; struct buffer_head *it;
ext4_debug("clear inode block %#04lx (+%d)\n", block, bit); 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))) { if (IS_ERR(it = bclean(handle, sb, block))) {
err = PTR_ERR(it); err = PTR_ERR(it);
goto exit_bh; goto exit_bh;
...@@ -244,6 +281,10 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -244,6 +281,10 @@ static int setup_new_group_blocks(struct super_block *sb,
brelse(it); brelse(it);
ext4_set_bit(bit, bh->b_data); 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), mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
bh->b_data); bh->b_data);
ext4_journal_dirty_metadata(handle, bh); ext4_journal_dirty_metadata(handle, bh);
...@@ -271,7 +312,6 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -271,7 +312,6 @@ static int setup_new_group_blocks(struct super_block *sb,
return err; return err;
} }
/* /*
* Iterate through the groups which hold BACKUP superblock/GDT copies in an * 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 * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment