2020-03-31 10:51:27

by Jan Kara

[permalink] [raw]
Subject: [PATCH] ext4: Do not zeroout extents beyond i_disksize

We do not want to create initialized extents beyond end of file because
for e2fsck it is impossible to distinguish them from a case of corrupted
file size / extent tree and so it complains like:

Inode 12, i_size is 147456, should be 163840. Fix? no

Code in ext4_ext_convert_to_initialized() and
ext4_split_convert_extents() try to make sure it does not create
initialized extents beyond inode size however they check against
inode->i_size which is wrong. They should instead check against
EXT4_I(inode)->i_disksize which is the current inode size on disk.
That's what e2fsck is going to see in case of crash before all dirty
data is written. This bug manifests as generic/456 test failure (with
recent enough fstests where fsx got fixed to properly pass
FALLOC_KEEP_SIZE_FL flags to the kernel) when run with dioread_lock
mount option.

CC: [email protected]
Fixes: 21ca087a3891 ("ext4: Do not zero out uninitialized extents beyond i_size")
Signed-off-by: Jan Kara <[email protected]>
---
fs/ext4/extents.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 954013d6076b..c5e190fd4589 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3532,8 +3532,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
(unsigned long long)map->m_lblk, map_len);

sbi = EXT4_SB(inode->i_sb);
- eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits;
+ eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
+ >> inode->i_sb->s_blocksize_bits;
if (eof_block < map->m_lblk + map_len)
eof_block = map->m_lblk + map_len;

@@ -3785,8 +3785,8 @@ static int ext4_split_convert_extents(handle_t *handle,
__func__, inode->i_ino,
(unsigned long long)map->m_lblk, map->m_len);

- eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits;
+ eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
+ >> inode->i_sb->s_blocksize_bits;
if (eof_block < map->m_lblk + map->m_len)
eof_block = map->m_lblk + map->m_len;
/*
--
2.16.4


2020-03-31 13:36:08

by Lukas Czerner

[permalink] [raw]
Subject: Re: [PATCH] ext4: Do not zeroout extents beyond i_disksize

On Tue, Mar 31, 2020 at 12:50:16PM +0200, Jan Kara wrote:
> We do not want to create initialized extents beyond end of file because
> for e2fsck it is impossible to distinguish them from a case of corrupted
> file size / extent tree and so it complains like:
>
> Inode 12, i_size is 147456, should be 163840. Fix? no
>
> Code in ext4_ext_convert_to_initialized() and
> ext4_split_convert_extents() try to make sure it does not create
> initialized extents beyond inode size however they check against
> inode->i_size which is wrong. They should instead check against
> EXT4_I(inode)->i_disksize which is the current inode size on disk.
> That's what e2fsck is going to see in case of crash before all dirty
> data is written. This bug manifests as generic/456 test failure (with
> recent enough fstests where fsx got fixed to properly pass
> FALLOC_KEEP_SIZE_FL flags to the kernel) when run with dioread_lock
> mount option.

Makes sense, thanks.

Reviewed-by: Lukas Czerner <[email protected]>

-Lukas

>
> CC: [email protected]
> Fixes: 21ca087a3891 ("ext4: Do not zero out uninitialized extents beyond i_size")
> Signed-off-by: Jan Kara <[email protected]>
> ---
> fs/ext4/extents.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 954013d6076b..c5e190fd4589 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -3532,8 +3532,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
> (unsigned long long)map->m_lblk, map_len);
>
> sbi = EXT4_SB(inode->i_sb);
> - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
> - inode->i_sb->s_blocksize_bits;
> + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
> + >> inode->i_sb->s_blocksize_bits;
> if (eof_block < map->m_lblk + map_len)
> eof_block = map->m_lblk + map_len;
>
> @@ -3785,8 +3785,8 @@ static int ext4_split_convert_extents(handle_t *handle,
> __func__, inode->i_ino,
> (unsigned long long)map->m_lblk, map->m_len);
>
> - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
> - inode->i_sb->s_blocksize_bits;
> + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
> + >> inode->i_sb->s_blocksize_bits;
> if (eof_block < map->m_lblk + map->m_len)
> eof_block = map->m_lblk + map->m_len;
> /*
> --
> 2.16.4
>

2020-04-10 15:13:15

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH] ext4: Do not zeroout extents beyond i_disksize

On Tue 31-03-20 12:50:16, Jan Kara wrote:
> We do not want to create initialized extents beyond end of file because
> for e2fsck it is impossible to distinguish them from a case of corrupted
> file size / extent tree and so it complains like:
>
> Inode 12, i_size is 147456, should be 163840. Fix? no
>
> Code in ext4_ext_convert_to_initialized() and
> ext4_split_convert_extents() try to make sure it does not create
> initialized extents beyond inode size however they check against
> inode->i_size which is wrong. They should instead check against
> EXT4_I(inode)->i_disksize which is the current inode size on disk.
> That's what e2fsck is going to see in case of crash before all dirty
> data is written. This bug manifests as generic/456 test failure (with
> recent enough fstests where fsx got fixed to properly pass
> FALLOC_KEEP_SIZE_FL flags to the kernel) when run with dioread_lock
> mount option.
>
> CC: [email protected]
> Fixes: 21ca087a3891 ("ext4: Do not zero out uninitialized extents beyond i_size")
> Signed-off-by: Jan Kara <[email protected]>

Ping Ted? Did this patch get lost?

Honza

> ---
> fs/ext4/extents.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 954013d6076b..c5e190fd4589 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -3532,8 +3532,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
> (unsigned long long)map->m_lblk, map_len);
>
> sbi = EXT4_SB(inode->i_sb);
> - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
> - inode->i_sb->s_blocksize_bits;
> + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
> + >> inode->i_sb->s_blocksize_bits;
> if (eof_block < map->m_lblk + map_len)
> eof_block = map->m_lblk + map_len;
>
> @@ -3785,8 +3785,8 @@ static int ext4_split_convert_extents(handle_t *handle,
> __func__, inode->i_ino,
> (unsigned long long)map->m_lblk, map->m_len);
>
> - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
> - inode->i_sb->s_blocksize_bits;
> + eof_block = (EXT4_I(inode)->i_disksize + inode->i_sb->s_blocksize - 1)
> + >> inode->i_sb->s_blocksize_bits;
> if (eof_block < map->m_lblk + map->m_len)
> eof_block = map->m_lblk + map->m_len;
> /*
> --
> 2.16.4
>
--
Jan Kara <[email protected]>
SUSE Labs, CR

2020-04-14 13:48:15

by Theodore Ts'o

[permalink] [raw]
Subject: Re: [PATCH] ext4: Do not zeroout extents beyond i_disksize

On Tue, Mar 31, 2020 at 12:50:16PM +0200, Jan Kara wrote:
> We do not want to create initialized extents beyond end of file because
> for e2fsck it is impossible to distinguish them from a case of corrupted
> file size / extent tree and so it complains like:
>
> Inode 12, i_size is 147456, should be 163840. Fix? no
>
> Code in ext4_ext_convert_to_initialized() and
> ext4_split_convert_extents() try to make sure it does not create
> initialized extents beyond inode size however they check against
> inode->i_size which is wrong. They should instead check against
> EXT4_I(inode)->i_disksize which is the current inode size on disk.
> That's what e2fsck is going to see in case of crash before all dirty
> data is written. This bug manifests as generic/456 test failure (with
> recent enough fstests where fsx got fixed to properly pass
> FALLOC_KEEP_SIZE_FL flags to the kernel) when run with dioread_lock
> mount option.
>
> CC: [email protected]
> Fixes: 21ca087a3891 ("ext4: Do not zero out uninitialized extents beyond i_size")
> Signed-off-by: Jan Kara <[email protected]>

Applied, thanks.

- Ted