summaryrefslogtreecommitdiffstats
path: root/ext4-fix-resize-when-resizing-within-single-group.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2012-02-21 14:42:16 -0500
committerJosh Boyer <jwboyer@redhat.com>2012-02-21 14:42:33 -0500
commit598ed8b2a0012e687d94d80a04d7e47cd1aad045 (patch)
tree43812ec9dea6253edffaaba96ee39f561a7d8901 /ext4-fix-resize-when-resizing-within-single-group.patch
parent292a6915db21e6582e5a0d09a17aa60d04d5157a (diff)
downloadkernel-598ed8b2a0012e687d94d80a04d7e47cd1aad045.tar.gz
kernel-598ed8b2a0012e687d94d80a04d7e47cd1aad045.tar.xz
kernel-598ed8b2a0012e687d94d80a04d7e47cd1aad045.zip
ext4: fix resize when resizing within single group (rhbz 786454)
Diffstat (limited to 'ext4-fix-resize-when-resizing-within-single-group.patch')
-rw-r--r--ext4-fix-resize-when-resizing-within-single-group.patch82
1 files changed, 82 insertions, 0 deletions
diff --git a/ext4-fix-resize-when-resizing-within-single-group.patch b/ext4-fix-resize-when-resizing-within-single-group.patch
new file mode 100644
index 000000000..9d911b425
--- /dev/null
+++ b/ext4-fix-resize-when-resizing-within-single-group.patch
@@ -0,0 +1,82 @@
+From a0ade1deb86d2325aecc36272bb4505a6eec9235 Mon Sep 17 00:00:00 2001
+From: Lukas Czerner <lczerner@redhat.com>
+Date: Mon, 20 Feb 2012 23:02:06 -0500
+Subject: [PATCH] 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>
+---
+ fs/ext4/resize.c | 14 ++++++++------
+ 1 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
+index f9d948f..3fed79d 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)
+ ext4_fsblk_t o_blocks_count;
+ ext4_group_t o_group;
+ ext4_group_t n_group;
+- ext4_grpblk_t offset;
++ ext4_grpblk_t offset, add;
+ unsigned long n_desc_blocks;
+ unsigned long o_desc_blocks;
+ unsigned long desc_blocks;
+@@ -1605,7 +1605,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
+ return 0;
+
+ ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
+- ext4_get_group_no_and_offset(sb, o_blocks_count, &o_group, &offset);
++ ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset);
+
+ n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) /
+ EXT4_DESC_PER_BLOCK(sb);
+@@ -1634,10 +1634,12 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
+ }
+ brelse(bh);
+
+- if (offset != 0) {
+- /* extend the last group */
+- ext4_grpblk_t add;
+- add = EXT4_BLOCKS_PER_GROUP(sb) - offset;
++ /* extend the last group */
++ if (n_group == o_group)
++ add = n_blocks_count - o_blocks_count;
++ else
++ add = EXT4_BLOCKS_PER_GROUP(sb) - (offset + 1);
++ if (add > 0) {
+ err = ext4_group_extend_no_check(sb, o_blocks_count, add);
+ if (err)
+ goto out;
+--
+1.7.6.5
+