Commit 1c2d1421 authored by Jan Kara's avatar Jan Kara

ext2: Fix underflow in ext2_max_size()

When ext2 filesystem is created with 64k block size, ext2_max_size()
will return value less than 0. Also, we cannot write any file in this fs
since the sb->maxbytes is less than 0. The core of the problem is that
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.

File size limits computed with the new function for the full range of
possible block sizes look like:

bits file_size
10     17247252480
11    275415851008
12   2196873666560
13   2197948973056
14   2198486220800
15   2198754754560
16   2198888906752

CC: stable@vger.kernel.org
Reported-by: default avataryangerkun <yangerkun@huawei.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 4bc74ba1
...@@ -757,7 +757,8 @@ static loff_t ext2_max_size(int bits) ...@@ -757,7 +757,8 @@ static loff_t ext2_max_size(int bits)
{ {
loff_t res = EXT2_NDIR_BLOCKS; loff_t res = EXT2_NDIR_BLOCKS;
int meta_blocks; int meta_blocks;
loff_t upper_limit; unsigned int upper_limit;
unsigned int ppb = 1 << (bits-2);
/* This is calculated to be the largest file size for a /* This is calculated to be the largest file size for a
* dense, file such that the total number of * dense, file such that the total number of
...@@ -771,24 +772,34 @@ static loff_t ext2_max_size(int bits) ...@@ -771,24 +772,34 @@ static loff_t ext2_max_size(int bits)
/* total blocks in file system block size */ /* total blocks in file system block size */
upper_limit >>= (bits - 9); upper_limit >>= (bits - 9);
/* Compute how many blocks we can address by block tree */
res += 1LL << (bits-2);
res += 1LL << (2*(bits-2));
res += 1LL << (3*(bits-2));
/* Does block tree limit file size? */
if (res < upper_limit)
goto check_lfs;
res = upper_limit;
/* How many metadata blocks are needed for addressing upper_limit? */
upper_limit -= EXT2_NDIR_BLOCKS;
/* indirect blocks */ /* indirect blocks */
meta_blocks = 1; meta_blocks = 1;
upper_limit -= ppb;
/* double indirect blocks */ /* double indirect blocks */
meta_blocks += 1 + (1LL << (bits-2)); if (upper_limit < ppb * ppb) {
/* tripple indirect blocks */ meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb);
meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); res -= meta_blocks;
goto check_lfs;
upper_limit -= meta_blocks; }
upper_limit <<= bits; meta_blocks += 1 + ppb;
upper_limit -= ppb * ppb;
res += 1LL << (bits-2); /* tripple indirect blocks for the rest */
res += 1LL << (2*(bits-2)); meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb) +
res += 1LL << (3*(bits-2)); DIV_ROUND_UP(upper_limit, ppb*ppb);
res -= meta_blocks;
check_lfs:
res <<= bits; res <<= bits;
if (res > upper_limit)
res = upper_limit;
if (res > MAX_LFS_FILESIZE) if (res > MAX_LFS_FILESIZE)
res = MAX_LFS_FILESIZE; res = MAX_LFS_FILESIZE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment