Re: [f2fs-dev] [PATCH] f2fs: compress: fix to handle race between truncate and writeback
From: Zhiguo Niu
Date: Thu Sep 10 2026 - 03:29:21 EST
Chao Yu via Linux-f2fs-devel <linux-f2fs-devel@xxxxxxxxxxxxxxxxxxxxx>
于2026年9月10日周四 10:24写道:
>
> From: Chao Yu <chao@xxxxxxxxxx>
>
> fsstress reports a kernel BUG in f2fs_truncate_partial_cluster():
>
> kernel BUG at fs/f2fs/compress.c:1238!
> RIP: 0010:f2fs_truncate_partial_cluster+0x292/0x2a0
> Call Trace:
> <TASK>
> f2fs_truncate+0xf6/0x210
> f2fs_setattr+0x6b7/0x770
> notify_change+0x33b/0x520
> do_truncate+0xc2/0xf0
> vfs_truncate+0x153/0x1d0
> ksys_truncate+0x78/0xd0
> __x64_sys_truncate+0x16/0x20
> do_syscall_64+0xbe/0x540
>
> The root cause is that Thread A (truncate) and Thread B (background
> writeback or fsync) can race as follows:
>
> Thread A Thread B
> - f2fs_setattr
> - f2fs_truncate
> - f2fs_truncate_blocks
> - f2fs_truncate_partial_cluster
> - f2fs_is_compressed_cluster
> return 1
> - f2fs_write_cache_pages
> - f2fs_write_multi_pages
> - f2fs_write_raw_pages
> - f2fs_write_single_data_page
> dn.data_blkaddr != COMPRESS_ADDR
> (cluster converted to normal)
> - f2fs_prepare_compress_overwrite
> - f2fs_is_compressed_cluster
> return 0
> - return 0
> - f2fs_bug_on(sbi, err == 0): BUG!
>
> Writeback path does not acquire i_gc_rwsem or filemap_invalidate_lock.
> When a compressed cluster fails compression during writeback, it is
> overwritten with raw data blocks. If Thread A checked
> f2fs_is_compressed_cluster() before the conversion, but calls
> f2fs_prepare_compress_overwrite() after the conversion,
> f2fs_prepare_compress_overwrite() returns 0 because the cluster is no
> longer a compressed cluster.
>
> To fix this, remove the f2fs_bug_on() and retry checking the cluster status
> when f2fs_prepare_compress_overwrite() returns 0, so that it can fall back
> to f2fs_do_truncate_blocks() to handle it as a normal cluster.
>
> Cc: stable@xxxxxxxxxx
> Fixes: 3265d3db1f16 ("f2fs: support partial truncation on compressed inode")
> Signed-off-by: Chao Yu <chao@xxxxxxxxxx>
> ---
> fs/f2fs/compress.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index ce88092d9ce2..e1cc7185428e 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1222,6 +1222,7 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock)
> int i;
> int err;
>
> +repeat:
> err = f2fs_is_compressed_cluster(inode, start_idx);
> if (err < 0)
> return err;
> @@ -1233,11 +1234,10 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock)
> /* truncate compressed cluster */
> err = f2fs_prepare_compress_overwrite(inode, &pagep,
> start_idx, &fsdata);
> + if (err == 0)
> + goto repeat;
Hi Chao,
some comments here will be easier to understand?
other LGTM
Reviewed-by: Zhiguo Niu <zhiguo.niu@xxxxxxxxxx>
thanks!
>
> - /* should not be a normal cluster */
> - f2fs_bug_on(F2FS_I_SB(inode), err == 0);
> -
> - if (err <= 0)
> + if (err < 0)
> return err;
>
> rpages = fsdata;
> --
> 2.49.0
>
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@xxxxxxxxxxxxxxxxxxxxx
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel