add patch set-ext4_dax_aops-for-dax-files
[ext4-patch-queue.git] / truncate-resize-size-to-avoid-too-small-last-bg
blob198b39e326c614c128f7017c054ed8091b922a24
1 ext4: fix online resize's handling of a too-small final block group
3 Avoid growing the file system to an extent so that the last block
4 group is too small to hold all of the metadata that must be stored in
5 the block group.
7 This problem can be triggered with the following reproducer:
9 umount /mnt
10 mke2fs -F -m0 -b 4096 -t ext4 -O resize_inode,^has_journal \
11         -E resize=1073741824 /tmp/foo.img 128M
12 mount /tmp/foo.img /mnt
13 truncate --size 1708M /tmp/foo.img
14 resize2fs /dev/loop0 295400
15 umount /mnt
16 e2fsck -fy /tmp/foo.img
18 Reported-by: Torsten Hilbrich <torsten.hilbrich@secunet.com>
19 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
20 Cc: stable@vger.kernel.org
21 ---
22  fs/ext4/resize.c | 20 ++++++++++++++++++++
23  1 file changed, 20 insertions(+)
25 diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
26 index e5fb38451a73..33655a6eff4d 100644
27 --- a/fs/ext4/resize.c
28 +++ b/fs/ext4/resize.c
29 @@ -1986,6 +1986,26 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
30                 }
31         }
33 +       /*
34 +        * Make sure the last group has enough space so that it's
35 +        * guaranteed to have enough space for all metadata blocks
36 +        * that it might need to hold.  (We might not need to store
37 +        * the inode table blocks in the last block group, but there
38 +        * will be cases where this might be needed.)
39 +        */
40 +       if ((ext4_group_first_block_no(sb, n_group) +
41 +            ext4_group_overhead_blocks(sb, n_group) + 2 +
42 +            sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) {
43 +               n_blocks_count = ext4_group_first_block_no(sb, n_group);
44 +               n_group--;
45 +               n_blocks_count_retry = 0;
46 +               if (resize_inode) {
47 +                       iput(resize_inode);
48 +                       resize_inode = NULL;
49 +               }
50 +               goto retry;
51 +       }
53         /* extend the last group */
54         if (n_group == o_group)
55                 add = n_blocks_count - o_blocks_count;