| From f0a459dec5495a3580f8d784555e6f8f3bf7f263 Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Mon, 3 Sep 2018 22:19:43 -0400 |
| Subject: ext4: fix online resize's handling of a too-small final block group |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| 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> |
| |
| --- |
| fs/ext4/resize.c | 20 ++++++++++++++++++++ |
| 1 file changed, 20 insertions(+) |
| |
| --- a/fs/ext4/resize.c |
| +++ b/fs/ext4/resize.c |
| @@ -1956,6 +1956,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; |