diff mbox series

[v2,3/4] ext4: don't return error if huge_file feature mismatch

Message ID 20210819065704.1248402-4-yi.zhang@huawei.com
State Superseded
Headers show
Series ext4: fix a inode checksum error | expand

Commit Message

Zhang Yi Aug. 19, 2021, 6:57 a.m. UTC
In ext4_inode_blocks_set(), huge_file feature should exist when setting
i_blocks beyond a 32 bit variable could be represented, return EFBIG if
not. This error should never happen in theory since sb->s_maxbytes should
not have allowed this, and we have already init sb->s_maxbytes according
to this feature in ext4_fill_super(). So switch to use WARN_ON_ONCE
instead.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
---
 fs/ext4/inode.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

Comments

Jan Kara Aug. 19, 2021, 10:26 a.m. UTC | #1
On Thu 19-08-21 14:57:03, Zhang Yi wrote:
> In ext4_inode_blocks_set(), huge_file feature should exist when setting
> i_blocks beyond a 32 bit variable could be represented, return EFBIG if
> not. This error should never happen in theory since sb->s_maxbytes should
> not have allowed this, and we have already init sb->s_maxbytes according
> to this feature in ext4_fill_super(). So switch to use WARN_ON_ONCE
> instead.
> 
> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
> ---

One comment below:

> @@ -4918,10 +4918,15 @@ static int ext4_inode_blocks_set(handle_t *handle,
>  		raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
>  		raw_inode->i_blocks_high = 0;
>  		ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
> -		return 0;
> +		return;
>  	}
> -	if (!ext4_has_feature_huge_file(sb))
> -		return -EFBIG;
> +
> +	/*
> +	 * This should never happen since sb->s_maxbytes should not have
> +	 * allowed this, which was set according to the huge_file feature
> +	 * in ext4_fill_super().
> +	 */
> +	WARN_ON_ONCE(!ext4_has_feature_huge_file(sb));

Thinking about this a bit more, this could also happen due to fs
corruption. So we probably need to call ext4_error_inode() here instead of
WARN_ON_ONCE(). Also it will result in properly marking fs as having
errors. But since we hold i_raw_lock at this call site we need to
keep the error bail out from ext4_inode_blocks_set() and in
ext4_do_update_inode() finish updating inode and then call
ext4_error_inode() after dropping i_raw_lock.

								Honza
Zhang Yi Aug. 19, 2021, 1:11 p.m. UTC | #2
On 2021/8/19 18:26, Jan Kara wrote:
> On Thu 19-08-21 14:57:03, Zhang Yi wrote:
>> In ext4_inode_blocks_set(), huge_file feature should exist when setting
>> i_blocks beyond a 32 bit variable could be represented, return EFBIG if
>> not. This error should never happen in theory since sb->s_maxbytes should
>> not have allowed this, and we have already init sb->s_maxbytes according
>> to this feature in ext4_fill_super(). So switch to use WARN_ON_ONCE
>> instead.
>>
>> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
>> ---
> 
> One comment below:
> 
>> @@ -4918,10 +4918,15 @@ static int ext4_inode_blocks_set(handle_t *handle,
>>  		raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
>>  		raw_inode->i_blocks_high = 0;
>>  		ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
>> -		return 0;
>> +		return;
>>  	}
>> -	if (!ext4_has_feature_huge_file(sb))
>> -		return -EFBIG;
>> +
>> +	/*
>> +	 * This should never happen since sb->s_maxbytes should not have
>> +	 * allowed this, which was set according to the huge_file feature
>> +	 * in ext4_fill_super().
>> +	 */
>> +	WARN_ON_ONCE(!ext4_has_feature_huge_file(sb));
> 
> Thinking about this a bit more, this could also happen due to fs
> corruption. So we probably need to call ext4_error_inode() here instead of
> WARN_ON_ONCE(). Also it will result in properly marking fs as having
> errors. But since we hold i_raw_lock at this call site we need to
> keep the error bail out from ext4_inode_blocks_set() and in
> ext4_do_update_inode() finish updating inode and then call
> ext4_error_inode() after dropping i_raw_lock.
> 
Yes, make sense, ext4_error_inode() is more reasonable.

Thanks,
Yi.
diff mbox series

Patch

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index eae1b2d0b550..d0d7a5295bf9 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4902,9 +4902,9 @@  struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
 	return ERR_PTR(ret);
 }
 
-static int ext4_inode_blocks_set(handle_t *handle,
-				struct ext4_inode *raw_inode,
-				struct ext4_inode_info *ei)
+static void ext4_inode_blocks_set(handle_t *handle,
+				  struct ext4_inode *raw_inode,
+				  struct ext4_inode_info *ei)
 {
 	struct inode *inode = &(ei->vfs_inode);
 	u64 i_blocks = READ_ONCE(inode->i_blocks);
@@ -4918,10 +4918,15 @@  static int ext4_inode_blocks_set(handle_t *handle,
 		raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
 		raw_inode->i_blocks_high = 0;
 		ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
-		return 0;
+		return;
 	}
-	if (!ext4_has_feature_huge_file(sb))
-		return -EFBIG;
+
+	/*
+	 * This should never happen since sb->s_maxbytes should not have
+	 * allowed this, which was set according to the huge_file feature
+	 * in ext4_fill_super().
+	 */
+	WARN_ON_ONCE(!ext4_has_feature_huge_file(sb));
 
 	if (i_blocks <= 0xffffffffffffULL) {
 		/*
@@ -4938,7 +4943,6 @@  static int ext4_inode_blocks_set(handle_t *handle,
 		raw_inode->i_blocks_lo   = cpu_to_le32(i_blocks);
 		raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
 	}
-	return 0;
 }
 
 static void __ext4_update_other_inode_time(struct super_block *sb,
@@ -5029,11 +5033,7 @@  static int ext4_do_update_inode(handle_t *handle,
 	if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
 		memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
 
-	err = ext4_inode_blocks_set(handle, raw_inode, ei);
-	if (err) {
-		spin_unlock(&ei->i_raw_lock);
-		goto out_brelse;
-	}
+	ext4_inode_blocks_set(handle, raw_inode, ei);
 
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	i_uid = i_uid_read(inode);