ext2: Fix underflow in ext2_max_size()
commit 1c2d14212b
upstream.
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: yangerkun <yangerkun@huawei.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
b22d9f07fc
Коммит
7412f34ff8
|
@ -754,7 +754,8 @@ static loff_t ext2_max_size(int bits)
|
|||
{
|
||||
loff_t res = EXT2_NDIR_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
|
||||
* dense, file such that the total number of
|
||||
|
@ -768,24 +769,34 @@ static loff_t ext2_max_size(int bits)
|
|||
/* total blocks in file system block size */
|
||||
upper_limit >>= (bits - 9);
|
||||
|
||||
|
||||
/* indirect blocks */
|
||||
meta_blocks = 1;
|
||||
/* 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;
|
||||
|
||||
/* Compute how many blocks we can address by block tree */
|
||||
res += 1LL << (bits-2);
|
||||
res += 1LL << (2*(bits-2));
|
||||
res += 1LL << (3*(bits-2));
|
||||
res <<= bits;
|
||||
if (res > upper_limit)
|
||||
res = upper_limit;
|
||||
/* 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 */
|
||||
meta_blocks = 1;
|
||||
upper_limit -= ppb;
|
||||
/* double indirect blocks */
|
||||
if (upper_limit < ppb * ppb) {
|
||||
meta_blocks += 1 + DIV_ROUND_UP(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(upper_limit, ppb) +
|
||||
DIV_ROUND_UP(upper_limit, ppb*ppb);
|
||||
res -= meta_blocks;
|
||||
check_lfs:
|
||||
res <<= bits;
|
||||
if (res > MAX_LFS_FILESIZE)
|
||||
res = MAX_LFS_FILESIZE;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче