[lvc-project] [PATCH RFC] ext4: add i_data_sem protection in ext4_destroy_inline_data_nolock()
Fedor Pchelkin
pchelkin at ispras.ru
Tue Nov 4 12:39:30 MSK 2025
On Tue, 04. Nov 09:33, Alexey Nepomnyashih wrote:
> Fix a race between inline data destruction and block mapping.
>
> The function ext4_destroy_inline_data_nolock() changes the inode data
> layout by clearing EXT4_INODE_INLINE_DATA and setting EXT4_INODE_EXTENTS.
> At the same time, another thread may execute ext4_map_blocks(), which
> tests EXT4_INODE_EXTENTS to decide whether to call ext4_ext_map_blocks()
> or ext4_ind_map_blocks().
>
> Without i_data_sem protection, ext4_ind_map_blocks() may receive inode
> with EXT4_INODE_EXTENTS flag and triggering assert.
>
> kernel BUG at fs/ext4/indirect.c:546!
> EXT4-fs (loop2): unmounting filesystem.
> invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
А я ведь ещё просто не успел ответить на письмо в lvc-patches...
Зря здесь версию ядра убрали из репорта - без неё номера строк теряют
смысл. Впрочем, раз уже отправили, давайте ждать какого-то фидбэка,
наиболее активно отвечающий там вроде Jan Kara.
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
> RIP: 0010:ext4_ind_map_blocks.cold+0x2b/0x5a fs/ext4/indirect.c:546
>
> Call Trace:
> <TASK>
> ext4_map_blocks+0xb9b/0x16f0 fs/ext4/inode.c:681
> _ext4_get_block+0x242/0x590 fs/ext4/inode.c:822
> ext4_block_write_begin+0x48b/0x12c0 fs/ext4/inode.c:1124
> ext4_write_begin+0x598/0xef0 fs/ext4/inode.c:1255
> ext4_da_write_begin+0x21e/0x9c0 fs/ext4/inode.c:3000
> generic_perform_write+0x259/0x5d0 mm/filemap.c:3846
> ext4_buffered_write_iter+0x15b/0x470 fs/ext4/file.c:285
> ext4_file_write_iter+0x8e0/0x17f0 fs/ext4/file.c:679
> call_write_iter include/linux/fs.h:2271 [inline]
> do_iter_readv_writev+0x212/0x3c0 fs/read_write.c:735
> do_iter_write+0x186/0x710 fs/read_write.c:861
> vfs_iter_write+0x70/0xa0 fs/read_write.c:902
> iter_file_splice_write+0x73b/0xc90 fs/splice.c:685
> do_splice_from fs/splice.c:763 [inline]
> direct_splice_actor+0x10f/0x170 fs/splice.c:950
> splice_direct_to_actor+0x33a/0xa10 fs/splice.c:896
> do_splice_direct+0x1a9/0x280 fs/splice.c:1002
> do_sendfile+0xb13/0x12c0 fs/read_write.c:1255
> __do_sys_sendfile64 fs/read_write.c:1323 [inline]
> __se_sys_sendfile64 fs/read_write.c:1309 [inline]
> __x64_sys_sendfile64+0x1cf/0x210 fs/read_write.c:1309
> do_syscall_x64 arch/x86/entry/common.c:51 [inline]
> do_syscall_64+0x35/0x80 arch/x86/entry/common.c:81
> entry_SYSCALL_64_after_hwframe+0x6e/0xd8
>
> Fixes: c755e251357a ("ext4: fix deadlock between inline_data and ext4_expand_extra_isize_ea()")
> Cc: stable at vger.kernel.org # v4.11+
> Signed-off-by: Alexey Nepomnyashih <sdl at nppct.ru>
> ---
> fs/ext4/inline.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
> index 1b094a4f3866..ef7821f7fd26 100644
> --- a/fs/ext4/inline.c
> +++ b/fs/ext4/inline.c
> @@ -446,9 +446,13 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
> if (!ei->i_inline_off)
> return 0;
>
> + down_write(&ei->i_data_sem);
> +
> error = ext4_get_inode_loc(inode, &is.iloc);
> - if (error)
> + if (error) {
> + up_write(&ei->i_data_sem);
> return error;
> + }
>
> error = ext4_xattr_ibody_find(inode, &i, &is);
> if (error)
> @@ -487,6 +491,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
> brelse(is.iloc.bh);
> if (error == -ENODATA)
> error = 0;
> + up_write(&ei->i_data_sem);
> return error;
> }
>
> --
> 2.43.0
More information about the lvc-project
mailing list