summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2018-09-03 22:19:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-29 03:07:34 -0700
commit205dc0da96dffe78c6684a37ee0b574c929f5155 (patch)
treef9a5b47b3c27a6e41bfef5feb47ba15c38d4ea24
parent67770b40a351bfaaa96ed8b5dae4c17528275263 (diff)
ext4: fix online resize's handling of a too-small final block group
commit f0a459dec5495a3580f8d784555e6f8f3bf7f263 upstream. Avoid growing the file system to an extent so that the last block group is too small to hold all of the metadata that must be stored in the block group. This problem can be triggered with the following reproducer: umount /mnt mke2fs -F -m0 -b 4096 -t ext4 -O resize_inode,^has_journal \ -E resize=1073741824 /tmp/foo.img 128M mount /tmp/foo.img /mnt truncate --size 1708M /tmp/foo.img resize2fs /dev/loop0 295400 umount /mnt e2fsck -fy /tmp/foo.img Reported-by: Torsten Hilbrich <torsten.hilbrich@secunet.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/ext4/resize.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index eb720d9e2953..5b56aa6c13f2 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1954,6 +1954,26 @@ retry:
}
}
+ /*
+ * Make sure the last group has enough space so that it's
+ * guaranteed to have enough space for all metadata blocks
+ * that it might need to hold. (We might not need to store
+ * the inode table blocks in the last block group, but there
+ * will be cases where this might be needed.)
+ */
+ if ((ext4_group_first_block_no(sb, n_group) +
+ ext4_group_overhead_blocks(sb, n_group) + 2 +
+ sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) {
+ n_blocks_count = ext4_group_first_block_no(sb, n_group);
+ n_group--;
+ n_blocks_count_retry = 0;
+ if (resize_inode) {
+ iput(resize_inode);
+ resize_inode = NULL;
+ }
+ goto retry;
+ }
+
/* extend the last group */
if (n_group == o_group)
add = n_blocks_count - o_blocks_count;