On Mon 27-11-23 14:33:13, Baokun Li wrote: > For files with logical blocks close to EXT_MAX_BLOCKS, the file size > predicted in ext4_mb_normalize_request() may exceed EXT_MAX_BLOCKS. > This can cause some blocks to be preallocated that will not be used. > And after [Fixes], the following issue may be triggered: > > ========================================================= > kernel BUG at fs/ext4/mballoc.c:4653! > Internal error: Oops - BUG: 00000000f2000800 [#1] SMP > CPU: 1 PID: 2357 Comm: xfs_io 6.7.0-rc2-00195-g0f5cc96c367f > Hardware name: linux,dummy-virt (DT) > pc : ext4_mb_use_inode_pa+0x148/0x208 > lr : ext4_mb_use_inode_pa+0x98/0x208 > Call trace: > ext4_mb_use_inode_pa+0x148/0x208 > ext4_mb_new_inode_pa+0x240/0x4a8 > ext4_mb_use_best_found+0x1d4/0x208 > ext4_mb_try_best_found+0xc8/0x110 > ext4_mb_regular_allocator+0x11c/0xf48 > ext4_mb_new_blocks+0x790/0xaa8 > ext4_ext_map_blocks+0x7cc/0xd20 > ext4_map_blocks+0x170/0x600 > ext4_iomap_begin+0x1c0/0x348 > ========================================================= > > Here is a calculation when adjusting ac_b_ex in ext4_mb_new_inode_pa(): > > ex.fe_logical = orig_goal_end - EXT4_C2B(sbi, ex.fe_len); > if (ac->ac_o_ex.fe_logical >= ex.fe_logical) > goto adjust_bex; > > The problem is that when orig_goal_end is subtracted from ac_b_ex.fe_len > it is still greater than EXT_MAX_BLOCKS, which causes ex.fe_logical to > overflow to a very small value, which ultimately triggers a BUG_ON in > ext4_mb_new_inode_pa() because pa->pa_free < len. > > The last logical block of an actual write request does not exceed > EXT_MAX_BLOCKS, so in ext4_mb_normalize_request() also avoids normalizing > the last logical block to exceed EXT_MAX_BLOCKS to avoid the above issue. > > The test case in [Link] can reproduce the above issue with 64k block size. > > Link: https://patchwork.kernel.org/project/fstests/list/?series=804003 > Cc: stable@xxxxxxxxxx # 6.4 > Fixes: 93cdf49f6eca ("ext4: Fix best extent lstart adjustment logic in ext4_mb_new_inode_pa()") > Signed-off-by: Baokun Li <libaokun1@xxxxxxxxxx> Yeah, good catch. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/ext4/mballoc.c | 4 ++++ > 1 file changed, 4 insertions(+) > > diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c > index 454d5612641e..d72b5e3c92ec 100644 > --- a/fs/ext4/mballoc.c > +++ b/fs/ext4/mballoc.c > @@ -4478,6 +4478,10 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, > start = max(start, rounddown(ac->ac_o_ex.fe_logical, > (ext4_lblk_t)EXT4_BLOCKS_PER_GROUP(ac->ac_sb))); > > + /* avoid unnecessary preallocation that may trigger assertions */ > + if (start + size > EXT_MAX_BLOCKS) > + size = EXT_MAX_BLOCKS - start; > + > /* don't cover already allocated blocks in selected range */ > if (ar->pleft && start <= ar->lleft) { > size -= ar->lleft + 1 - start; > -- > 2.31.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR