[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