All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] fix a bug in ext2_max_size
@ 2019-01-23 13:14 yangerkun
  2019-01-23 13:14 ` [PATCH 1/2] ext2: remove static of ext2_block_to_path yangerkun
  2019-01-23 13:14 ` [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size yangerkun
  0 siblings, 2 replies; 5+ messages in thread
From: yangerkun @ 2019-01-23 13:14 UTC (permalink / raw)
  To: jack; +Cc: miaoxie, yi.zhang, houtao1, yangerkun, linux-ext4

When mkfs.ext2 with '-b 65536' and mount(arm 64KB page size),
function mount_fs will trigger WARNNING 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.

yangerkun (2):
  ext2: remove static of ext2_block_to_path
  ext2: get the exact max filesize in ext2_max_size

 fs/ext2/ext2.h  |   1 +
 fs/ext2/inode.c |  16 ++++----
 fs/ext2/super.c | 115 ++++++++++++++++++++++++++++++++++++++++++++------------
 3 files changed, 101 insertions(+), 31 deletions(-)

-- 
2.9.5


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] ext2: remove static of ext2_block_to_path
  2019-01-23 13:14 [PATCH 0/2] fix a bug in ext2_max_size yangerkun
@ 2019-01-23 13:14 ` yangerkun
  2019-01-23 13:14 ` [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size yangerkun
  1 sibling, 0 replies; 5+ messages in thread
From: yangerkun @ 2019-01-23 13:14 UTC (permalink / raw)
  To: jack; +Cc: miaoxie, yi.zhang, houtao1, yangerkun, linux-ext4

This function will be used to get exact size in ext2_max_size future.

Signed-off-by: yangerkun <yangerkun@huawei.com>
---
 fs/ext2/ext2.h  |  1 +
 fs/ext2/inode.c | 16 ++++++++--------
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index e770cd1..86d5be1 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -772,6 +772,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
 extern struct inode *ext2_iget (struct super_block *, unsigned long);
 extern int ext2_write_inode (struct inode *, struct writeback_control *);
 extern void ext2_evict_inode(struct inode *);
+extern int ext2_block_to_path(struct super_block *sb, long i_block, int offsets[4], int *boundary);
 extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index e4bb938..f2833245 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -132,7 +132,6 @@ static inline int verify_chain(Indirect *from, Indirect *to)
 
 /**
  *	ext2_block_to_path - parse the block number into array of offsets
- *	@inode: inode in question (we are only interested in its superblock)
  *	@i_block: block number to be parsed
  *	@offsets: array to store the offsets in
  *      @boundary: set this non-zero if the referred-to block is likely to be
@@ -160,11 +159,11 @@ static inline int verify_chain(Indirect *from, Indirect *to)
  * get there at all.
  */
 
-static int ext2_block_to_path(struct inode *inode,
+int ext2_block_to_path(struct super_block *sb,
 			long i_block, int offsets[4], int *boundary)
 {
-	int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+	int ptrs = EXT2_ADDR_PER_BLOCK(sb);
+	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(sb);
 	const long direct_blocks = EXT2_NDIR_BLOCKS,
 		indirect_blocks = ptrs,
 		double_blocks = (1 << (ptrs_bits * 2));
@@ -172,7 +171,7 @@ static int ext2_block_to_path(struct inode *inode,
 	int final = 0;
 
 	if (i_block < 0) {
-		ext2_msg(inode->i_sb, KERN_WARNING,
+		ext2_msg(sb, KERN_WARNING,
 			"warning: %s: block < 0", __func__);
 	} else if (i_block < direct_blocks) {
 		offsets[n++] = i_block;
@@ -193,7 +192,7 @@ static int ext2_block_to_path(struct inode *inode,
 		offsets[n++] = i_block & (ptrs - 1);
 		final = ptrs;
 	} else {
-		ext2_msg(inode->i_sb, KERN_WARNING,
+		ext2_msg(sb, KERN_WARNING,
 			"warning: %s: block is too big", __func__);
 	}
 	if (boundary)
@@ -637,7 +636,8 @@ static int ext2_get_blocks(struct inode *inode,
 
 	BUG_ON(maxblocks == 0);
 
-	depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
+	depth = ext2_block_to_path(inode->i_sb, iblock,
+				offsets, &blocks_to_boundary);
 
 	if (depth == 0)
 		return -EIO;
@@ -1194,7 +1194,7 @@ static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
 	WARN_ON(!rwsem_is_locked(&ei->dax_sem));
 #endif
 
-	n = ext2_block_to_path(inode, iblock, offsets, NULL);
+	n = ext2_block_to_path(inode->i_sb, iblock, offsets, NULL);
 	if (n == 0)
 		return;
 
-- 
2.9.5


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size
  2019-01-23 13:14 [PATCH 0/2] fix a bug in ext2_max_size yangerkun
  2019-01-23 13:14 ` [PATCH 1/2] ext2: remove static of ext2_block_to_path yangerkun
@ 2019-01-23 13:14 ` yangerkun
  2019-01-29 16:42   ` Jan Kara
  1 sibling, 1 reply; 5+ messages in thread
From: yangerkun @ 2019-01-23 13:14 UTC (permalink / raw)
  To: jack; +Cc: miaoxie, yi.zhang, houtao1, yangerkun, linux-ext4

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@huawei.com>
---
 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


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size
  2019-01-23 13:14 ` [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size yangerkun
@ 2019-01-29 16:42   ` Jan Kara
  2019-01-31 11:42     ` yangerkun
  0 siblings, 1 reply; 5+ messages in thread
From: Jan Kara @ 2019-01-29 16:42 UTC (permalink / raw)
  To: yangerkun; +Cc: jack, miaoxie, yi.zhang, houtao1, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 5681 bytes --]

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@huawei.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...

								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
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

[-- Attachment #2: 0001-ext2-Fix-underflow-in-ext2_max_size.patch --]
[-- Type: text/x-patch, Size: 2640 bytes --]

From a06dc132deae0c0f9b7cb681940ba1e0b40b40dc Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 29 Jan 2019 17:17:24 +0100
Subject: [PATCH] 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   2198754689024
16   2198888775680

Reported-by: yangerkun <yangerkun@huawei.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext2/super.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 73b2d528237f..5cc04a2a78a1 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -758,6 +758,7 @@ static loff_t ext2_max_size(int bits)
 	loff_t res = EXT2_NDIR_BLOCKS;
 	int meta_blocks;
 	loff_t 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
@@ -771,24 +772,29 @@ static loff_t ext2_max_size(int bits)
 	/* total blocks in file system block size */
 	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 */
 	meta_blocks = 1;
+	upper_limit -= 1LL << (bits-2);
 	/* 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));
+	upper_limit -= 1LL << (2*(bits-2));
+	/* 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 > upper_limit)
-		res = upper_limit;
-
 	if (res > MAX_LFS_FILESIZE)
 		res = MAX_LFS_FILESIZE;
 
-- 
2.16.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size
  2019-01-29 16:42   ` Jan Kara
@ 2019-01-31 11:42     ` yangerkun
  0 siblings, 0 replies; 5+ messages in thread
From: yangerkun @ 2019-01-31 11:42 UTC (permalink / raw)
  To: Jan Kara; +Cc: miaoxie, yi.zhang, houtao1, linux-ext4



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@huawei.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@huawei.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
>>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-01-31 11:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-23 13:14 [PATCH 0/2] fix a bug in ext2_max_size yangerkun
2019-01-23 13:14 ` [PATCH 1/2] ext2: remove static of ext2_block_to_path yangerkun
2019-01-23 13:14 ` [PATCH 2/2] ext2: get the exact max filesize in ext2_max_size yangerkun
2019-01-29 16:42   ` Jan Kara
2019-01-31 11:42     ` yangerkun

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.