On Tue 01-03-22 19:17:04, Zhang Yi wrote: > when ext4 filesystem is created with 64k block size, ^extent and > ^huge_file features. the upper_limit would underflow during the > computations in ext4_max_bitmap_size(). The problem is the size of block > index tree for such large block size is more than i_blocks can carry. > So fix the computation to count with this possibility. After this fix, > the 'res' cannot overflow loff_t on the extreme case of filesystem with > huge_files and 64K block size, so this patch also revert commit > 75ca6ad408f4 ("ext4: fix loff_t overflow in ext4_max_bitmap_size()"). > > Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> Thanks! The patch looks good. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > v3->v2: rewrite change log and use ppb to compute 'res' blocks. > v2->v1: use DIV_ROUND_UP_ULL instead of DIV_ROUND_UP. > > fs/ext4/super.c | 46 +++++++++++++++++++++++++++++++--------------- > 1 file changed, 31 insertions(+), 15 deletions(-) > > diff --git a/fs/ext4/super.c b/fs/ext4/super.c > index c5021ca0a28a..bfba62206a14 100644 > --- a/fs/ext4/super.c > +++ b/fs/ext4/super.c > @@ -3468,8 +3468,9 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) > */ > static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) > { > - unsigned long long upper_limit, res = EXT4_NDIR_BLOCKS; > + loff_t upper_limit, res = EXT4_NDIR_BLOCKS; > int meta_blocks; > + unsigned int ppb = 1 << (bits - 2); > > /* > * This is calculated to be the largest file size for a dense, block > @@ -3501,27 +3502,42 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) > > } > > + /* Compute how many blocks we can address by block tree */ > + res += ppb; > + res += ppb * ppb; > + res += ((loff_t)ppb) * ppb * ppb; > + /* Compute how many metadata blocks are needed */ > + meta_blocks = 1; > + meta_blocks += 1 + ppb; > + meta_blocks += 1 + ppb + ppb * ppb; > + /* Does block tree limit file size? */ > + if (res + meta_blocks <= upper_limit) > + goto check_lfs; > + > + res = upper_limit; > + /* How many metadata blocks are needed for addressing upper_limit? */ > + upper_limit -= EXT4_NDIR_BLOCKS; > /* indirect blocks */ > meta_blocks = 1; > + upper_limit -= ppb; > /* double indirect blocks */ > - meta_blocks += 1 + (1LL << (bits-2)); > - /* tripple indirect blocks */ > - meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); > - > - upper_limit -= meta_blocks; > - upper_limit <<= bits; > - > - res += 1LL << (bits-2); > - res += 1LL << (2*(bits-2)); > - res += 1LL << (3*(bits-2)); > + if (upper_limit < ppb * ppb) { > + meta_blocks += 1 + DIV_ROUND_UP_ULL(upper_limit, ppb); > + res -= meta_blocks; > + goto check_lfs; > + } > + meta_blocks += 1 + ppb; > + upper_limit -= ppb * ppb; > + /* tripple indirect blocks for the rest */ > + meta_blocks += 1 + DIV_ROUND_UP_ULL(upper_limit, ppb) + > + DIV_ROUND_UP_ULL(upper_limit, ppb*ppb); > + res -= meta_blocks; > +check_lfs: > res <<= bits; > - if (res > upper_limit) > - res = upper_limit; > - > if (res > MAX_LFS_FILESIZE) > res = MAX_LFS_FILESIZE; > > - return (loff_t)res; > + return res; > } > > static ext4_fsblk_t descriptor_loc(struct super_block *sb, > -- > 2.31.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR