diff mbox series

[1/2] ext4: fix online resize's handling of a too-small final block group

Message ID 20180904022546.16351-1-tytso@mit.edu
State Accepted, archived
Headers show
Series [1/2] ext4: fix online resize's handling of a too-small final block group | expand

Commit Message

Theodore Ts'o Sept. 4, 2018, 2:25 a.m. UTC
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
---
 fs/ext4/resize.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Comments

Torsten Hilbrich Sept. 5, 2018, 5:54 a.m. UTC | #1
Am 04.09.2018 um 04:25 schrieb Theodore Ts'o:
> diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
> index e5fb38451a73..33655a6eff4d 100644
> --- a/fs/ext4/resize.c
> +++ b/fs/ext4/resize.c
> @@ -1986,6 +1986,26 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
>  		}
>  	}
>  
> +	/*
> +	 * 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;
> 

I successfully tested your fix in our system test where the problem was
initially found.

Thank you,

	Torsten
diff mbox series

Patch

diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index e5fb38451a73..33655a6eff4d 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1986,6 +1986,26 @@  int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
 		}
 	}
 
+	/*
+	 * 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;