lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Thu, 31 Jan 2019 19:42:06 +0800
From:   yangerkun <yangerkun@...wei.com>
To:     Jan Kara <jack@...e.cz>
CC:     <miaoxie@...wei.com>, <yi.zhang@...wei.com>, <houtao1@...wei.com>,
        <linux-ext4@...r.kernel.org>
Subject: Re: [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size



Jan Kara wrote on 2019/1/30 0:42:
> On Wed 23-01-19 21:14:09, yangerkun wrote:
>> When mkfs.ext2 with '-b 65536' and mount(arm 64KB page size), function
>> mount_fs will trigger WARNING since 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.
>>
>> Fix it by get the exact max file size. First, get the max depth for
>> indirect blocks and check does the max data blocks add indirect blocks
>> will execced upper_limit. If right, bisect to get exact data blocks
>> number which satisfy 'data blocks number + indirect blocks number ==
>> upper_limit'.
>>
>> Signed-off-by: yangerkun <yangerkun@...wei.com>
> 
> Thanks for the patches but I was really looking for something simpler.
> Something like the attached patch. Although your more precise function will
> raise the maximum file size by couple of kilobytes I don't think the
> complexity is really worth it...

Agree with you. A precise answer with so complexity function does not 
make sense. Also i have review and test your without any problem. I 
prefer your patch!

Reviewed-by: yangerkun <yangerkun@...wei.com>

Thanks a lot,
Kun.

> 
> 								Honza
> 
>> ---
>>   fs/ext2/super.c | 115 ++++++++++++++++++++++++++++++++++++++++++++------------
>>   1 file changed, 92 insertions(+), 23 deletions(-)
>>
>> diff --git a/fs/ext2/super.c b/fs/ext2/super.c
>> index 73b2d52..b3eb6e9 100644
>> --- a/fs/ext2/super.c
>> +++ b/fs/ext2/super.c
>> @@ -753,11 +753,16 @@ static int ext2_check_descriptors(struct super_block *sb)
>>    * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
>>    * We need to be 1 filesystem block less than the 2^32 sector limit.
>>    */
>> -static loff_t ext2_max_size(int bits)
>> +static loff_t ext2_max_size(struct super_block *sb, int bits)
>>   {
>> -	loff_t res = EXT2_NDIR_BLOCKS;
>> -	int meta_blocks;
>> +	loff_t res;
>> +	loff_t max_meta_blocks;
>> +	loff_t used_data_blocks;
>> +	loff_t max_data_blocks;
>>   	loff_t upper_limit;
>> +	int depth;
>> +	loff_t high, low;
>> +
>>   
>>   	/* This is calculated to be the largest file size for a
>>   	 * dense, file such that the total number of
>> @@ -771,24 +776,88 @@ static loff_t ext2_max_size(int bits)
>>   	/* total blocks in file system block size */
>>   	upper_limit >>= (bits - 9);
>>   
>> +	/* Try to get max depth of metadata blocks */
>> +	depth = 0;
>> +	max_meta_blocks = 0;
>> +	used_data_blocks = 0;
>> +	max_data_blocks = EXT2_NDIR_BLOCKS;
>> +	if (max_meta_blocks + max_data_blocks > upper_limit)
>> +		goto bisect;
>> +
>> +	depth++;
>> +	max_meta_blocks = 1;
>> +	used_data_blocks = max_data_blocks;
>> +	max_data_blocks += 1LL << (bits - 2);
>> +	if (max_meta_blocks + max_data_blocks > upper_limit)
>> +		goto bisect;
>> +
>> +	depth++;
>> +	max_meta_blocks += 1 + (1LL << (bits - 2));
>> +	used_data_blocks = max_data_blocks;
>> +	max_data_blocks += 1LL << (2 * (bits - 2));
>> +	if (max_meta_blocks + max_data_blocks > upper_limit)
>> +		goto bisect;
>> +
>> +	depth++;
>> +	max_meta_blocks += 1 + (1LL << (bits - 2)) + (1LL << (2 * (bits - 2)));
>> +	used_data_blocks = max_data_blocks;
>> +	max_data_blocks += 1LL << (3 * (bits - 2));
>> +	if (max_meta_blocks + max_data_blocks > upper_limit)
>> +		goto bisect;
>> +
>> +	goto out;
>> +bisect:
>> +	low = 0;
>> +	if (depth == 0)
>> +		high = EXT2_NDIR_BLOCKS;
>> +	else
>> +		high = 1 << (depth * (bits - 2));
>> +	while (low <= high) {
>> +		int offsets[4];
>> +		loff_t mid = (low + high) >> 1;
>> +		depth = ext2_block_to_path(sb, mid + used_data_blocks - 1, offsets, NULL);
>> +		if (!depth)
>> +			return -EIO;
>> +
>> +		max_meta_blocks = 0;
>> +		if (depth == 1)
>> +			max_meta_blocks = 0;
>> +
>> +		if (depth == 2)
>> +			max_meta_blocks = 1;
>> +
>> +		if (depth == 3) {
>> +			/* Indirect blocks */
>> +			max_meta_blocks += 1;
>> +			/* Double indirect blocks */
>> +			max_meta_blocks += 1;
>> +			max_meta_blocks += offsets[1];
>> +		}
>>   
>> -	/* 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;
>> -
>> -	res += 1LL << (bits-2);
>> -	res += 1LL << (2*(bits-2));
>> -	res += 1LL << (3*(bits-2));
>> -	res <<= bits;
>> -	if (res > upper_limit)
>> -		res = upper_limit;
>> -
>> +		if (depth == 4) {
>> +			/* Indirect blocks */
>> +			max_meta_blocks += 1;
>> +			/* Double indirect blocks */
>> +			max_meta_blocks += 1 + (1 << (bits - 2));
>> +			/* Tripple indirect blocks */
>> +			max_meta_blocks += 1;
>> +			if (offsets[1])
>> +				max_meta_blocks += (offsets[1] - 1) * (1 << (bits - 2));
>> +
>> +			max_meta_blocks += 1;
>> +			max_meta_blocks += offsets[2];
>> +		}
>> +		if (max_meta_blocks + mid + used_data_blocks > upper_limit)
>> +			high = mid - 1;
>> +		if (max_meta_blocks + mid + used_data_blocks < upper_limit)
>> +			low = mid + 1;
>> +		if (max_meta_blocks + mid + used_data_blocks == upper_limit) {
>> +			max_data_blocks = mid + used_data_blocks;
>> +			break;
>> +		}
>> +	}
>> +out:
>> +	res = max_data_blocks << bits;
>>   	if (res > MAX_LFS_FILESIZE)
>>   		res = MAX_LFS_FILESIZE;
>>   
>> @@ -995,7 +1064,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
>>   		}
>>   	}
>>   
>> -	sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
>> +	sbi->s_addr_per_block_bits =
>> +		ilog2 (EXT2_ADDR_PER_BLOCK(sb));
>> +	sb->s_maxbytes = ext2_max_size(sb, sb->s_blocksize_bits);
>>   	sb->s_max_links = EXT2_LINK_MAX;
>>   
>>   	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
>> @@ -1035,8 +1106,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
>>   					sizeof (struct ext2_group_desc);
>>   	sbi->s_sbh = bh;
>>   	sbi->s_mount_state = le16_to_cpu(es->s_state);
>> -	sbi->s_addr_per_block_bits =
>> -		ilog2 (EXT2_ADDR_PER_BLOCK(sb));
>>   	sbi->s_desc_per_block_bits =
>>   		ilog2 (EXT2_DESC_PER_BLOCK(sb));
>>   
>> -- 
>> 2.9.5
>>

Powered by blists - more mailing lists