aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2012-02-20 23:02:06 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-02-20 23:02:06 -0500
commita0ade1deb86d2325aecc36272bb4505a6eec9235 (patch)
tree863f896ae46280dbcbbe5c31e9a3d2988c14c1fb /fs/ext4
parent266991b13890049ee1a6bb95b9817f06339ee3d7 (diff)
ext4: fix resize when resizing within single group
When resizing file system in the way that the new size of the file system is still in the same group (no new groups are added), then we can hit a BUG_ON in ext4_alloc_group_tables() BUG_ON(flex_gd->count == 0 || group_data == NULL); because flex_gd->count is zero. The reason is the missing check for such case, so the code always extend the last group fully and then attempt to add more groups, but at that time n_blocks_count is actually smaller than o_blocks_count. It can be easily reproduced like this: mkfs.ext4 -b 4096 /dev/sda 30M mount /dev/sda /mnt/test resize2fs /dev/sda 50M Fix this by checking whether the resize happens within the singe group and only add that many blocks into the last group to satisfy user request. Then o_blocks_count == n_blocks_count and the resize will exit successfully without and attempt to add more groups into the fs. Also fix mixing together block number and blocks count which might be confusing and can easily lead to off-by-one errors (but it is actually not the case here since the two occurrence of this mix-up will cancel each other). Signed-off-by: Lukas Czerner <lczerner@redhat.com> Reported-by: Milan Broz <mbroz@redhat.com> Reviewed-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/resize.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index f9d948f0eb86..3fed79da0d2c 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1582,7 +1582,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1582 ext4_fsblk_t o_blocks_count; 1582 ext4_fsblk_t o_blocks_count;
1583 ext4_group_t o_group; 1583 ext4_group_t o_group;
1584 ext4_group_t n_group; 1584 ext4_group_t n_group;
1585 ext4_grpblk_t offset; 1585 ext4_grpblk_t offset, add;
1586 unsigned long n_desc_blocks; 1586 unsigned long n_desc_blocks;
1587 unsigned long o_desc_blocks; 1587 unsigned long o_desc_blocks;
1588 unsigned long desc_blocks; 1588 unsigned long desc_blocks;
@@ -1605,7 +1605,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1605 return 0; 1605 return 0;
1606 1606
1607 ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset); 1607 ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
1608 ext4_get_group_no_and_offset(sb, o_blocks_count, &o_group, &offset); 1608 ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset);
1609 1609
1610 n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) / 1610 n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) /
1611 EXT4_DESC_PER_BLOCK(sb); 1611 EXT4_DESC_PER_BLOCK(sb);
@@ -1634,10 +1634,12 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1634 } 1634 }
1635 brelse(bh); 1635 brelse(bh);
1636 1636
1637 if (offset != 0) { 1637 /* extend the last group */
1638 /* extend the last group */ 1638 if (n_group == o_group)
1639 ext4_grpblk_t add; 1639 add = n_blocks_count - o_blocks_count;
1640 add = EXT4_BLOCKS_PER_GROUP(sb) - offset; 1640 else
1641 add = EXT4_BLOCKS_PER_GROUP(sb) - (offset + 1);
1642 if (add > 0) {
1641 err = ext4_group_extend_no_check(sb, o_blocks_count, add); 1643 err = ext4_group_extend_no_check(sb, o_blocks_count, add);
1642 if (err) 1644 if (err)
1643 goto out; 1645 goto out;