| From 801674f34ecfed033b062a0f217506b93c8d5e8a Mon Sep 17 00:00:00 2001 |
| From: Jan Kara <jack@suse.cz> |
| Date: Tue, 31 Mar 2020 12:50:16 +0200 |
| Subject: ext4: do not zeroout extents beyond i_disksize |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| commit 801674f34ecfed033b062a0f217506b93c8d5e8a upstream. |
| |
| 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: stable@vger.kernel.org |
| Fixes: 21ca087a3891 ("ext4: Do not zero out uninitialized extents beyond i_size") |
| Reviewed-by: Lukas Czerner <lczerner@redhat.com> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Link: https://lore.kernel.org/r/20200331105016.8674-1-jack@suse.cz |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/extents.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/fs/ext4/extents.c |
| +++ b/fs/ext4/extents.c |
| @@ -3549,8 +3549,8 @@ static int ext4_ext_convert_to_initializ |
| (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; |
| |
| @@ -3805,8 +3805,8 @@ static int ext4_split_convert_extents(ha |
| __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; |
| /* |