ext4: fix underflow in ext4_max_bitmap_size()
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
75ca6ad408
("ext4: fix loff_t overflow in ext4_max_bitmap_size()").
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20220301111704.2153829-1-yi.zhang@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
fd9b6fad66
commit
5c93e8ecd5
@ -3481,8 +3481,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
|
||||
@ -3514,27 +3515,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,
|
||||
|
Loading…
Reference in New Issue
Block a user