Skip to content

Commit baaae97

Browse files
zhangyi089tytso
authored andcommitted
ext4: make the updating inode data procedure atomic
Now that ext4_do_update_inode() return error before filling the whole inode data if we fail to set inode blocks in ext4_inode_blocks_set(). This error should never happen in theory since sb->s_maxbytes should not have allowed this, we have already init sb->s_maxbytes according to this feature in ext4_fill_super(). So even through that could only happen due to the filesystem corruption, we'd better to return after we finish updating the inode because it may left an uninitialized buffer and we could read this buffer later in "errors=continue" mode. This patch make the updating inode data procedure atomic, call EXT4_ERROR_INODE() after we dropping i_raw_lock after something bad happened, make sure that the inode is integrated, and also drop a BUG_ON and do some small cleanups. Signed-off-by: Zhang Yi <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 8e33fad commit baaae97

File tree

1 file changed

+28
-16
lines changed

1 file changed

+28
-16
lines changed

fs/ext4/inode.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4932,8 +4932,14 @@ static int ext4_inode_blocks_set(handle_t *handle,
49324932
ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
49334933
return 0;
49344934
}
4935+
4936+
/*
4937+
* This should never happen since sb->s_maxbytes should not have
4938+
* allowed this, sb->s_maxbytes was set according to the huge_file
4939+
* feature in ext4_fill_super().
4940+
*/
49354941
if (!ext4_has_feature_huge_file(sb))
4936-
return -EFBIG;
4942+
return -EFSCORRUPTED;
49374943

49384944
if (i_blocks <= 0xffffffffffffULL) {
49394945
/*
@@ -5036,16 +5042,14 @@ static int ext4_do_update_inode(handle_t *handle,
50365042

50375043
spin_lock(&ei->i_raw_lock);
50385044

5039-
/* For fields not tracked in the in-memory inode,
5040-
* initialise them to zero for new inodes. */
5045+
/*
5046+
* For fields not tracked in the in-memory inode, initialise them
5047+
* to zero for new inodes.
5048+
*/
50415049
if (ext4_test_inode_state(inode, EXT4_STATE_NEW))
50425050
memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
50435051

50445052
err = ext4_inode_blocks_set(handle, raw_inode, ei);
5045-
if (err) {
5046-
spin_unlock(&ei->i_raw_lock);
5047-
goto out_brelse;
5048-
}
50495053

50505054
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
50515055
i_uid = i_uid_read(inode);
@@ -5054,10 +5058,11 @@ static int ext4_do_update_inode(handle_t *handle,
50545058
if (!(test_opt(inode->i_sb, NO_UID32))) {
50555059
raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
50565060
raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
5057-
/*
5058-
* Fix up interoperability with old kernels. Otherwise, old inodes get
5059-
* re-used with the upper 16 bits of the uid/gid intact
5060-
*/
5061+
/*
5062+
* Fix up interoperability with old kernels. Otherwise,
5063+
* old inodes get re-used with the upper 16 bits of the
5064+
* uid/gid intact.
5065+
*/
50615066
if (ei->i_dtime && list_empty(&ei->i_orphan)) {
50625067
raw_inode->i_uid_high = 0;
50635068
raw_inode->i_gid_high = 0;
@@ -5126,31 +5131,37 @@ static int ext4_do_update_inode(handle_t *handle,
51265131
}
51275132
}
51285133

5129-
BUG_ON(!ext4_has_feature_project(inode->i_sb) &&
5130-
i_projid != EXT4_DEF_PROJID);
5134+
if (i_projid != EXT4_DEF_PROJID &&
5135+
!ext4_has_feature_project(inode->i_sb))
5136+
err = err ?: -EFSCORRUPTED;
51315137

51325138
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
51335139
EXT4_FITS_IN_INODE(raw_inode, ei, i_projid))
51345140
raw_inode->i_projid = cpu_to_le32(i_projid);
51355141

51365142
ext4_inode_csum_set(inode, raw_inode, ei);
51375143
spin_unlock(&ei->i_raw_lock);
5144+
if (err) {
5145+
EXT4_ERROR_INODE(inode, "corrupted inode contents");
5146+
goto out_brelse;
5147+
}
5148+
51385149
if (inode->i_sb->s_flags & SB_LAZYTIME)
51395150
ext4_update_other_inodes_time(inode->i_sb, inode->i_ino,
51405151
bh->b_data);
51415152

51425153
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
51435154
err = ext4_handle_dirty_metadata(handle, NULL, bh);
51445155
if (err)
5145-
goto out_brelse;
5156+
goto out_error;
51465157
ext4_clear_inode_state(inode, EXT4_STATE_NEW);
51475158
if (set_large_file) {
51485159
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access");
51495160
err = ext4_journal_get_write_access(handle, sb,
51505161
EXT4_SB(sb)->s_sbh,
51515162
EXT4_JTR_NONE);
51525163
if (err)
5153-
goto out_brelse;
5164+
goto out_error;
51545165
lock_buffer(EXT4_SB(sb)->s_sbh);
51555166
ext4_set_feature_large_file(sb);
51565167
ext4_superblock_csum_set(sb);
@@ -5160,9 +5171,10 @@ static int ext4_do_update_inode(handle_t *handle,
51605171
EXT4_SB(sb)->s_sbh);
51615172
}
51625173
ext4_update_inode_fsync_trans(handle, inode, need_datasync);
5174+
out_error:
5175+
ext4_std_error(inode->i_sb, err);
51635176
out_brelse:
51645177
brelse(bh);
5165-
ext4_std_error(inode->i_sb, err);
51665178
return err;
51675179
}
51685180

0 commit comments

Comments
 (0)