ext4: fix iloc.bh leak in ext4_fc_replay_inode() error paths
During code review, Joseph found that ext4_fc_replay_inode() calls
ext4_get_fc_inode_loc() to get the inode location, which holds a
reference to iloc.bh that must be released via brelse().
However, several error paths jump to the 'out' label without
releasing iloc.bh:
- ext4_handle_dirty_metadata() failure
- sync_dirty_buffer() failure
- ext4_mark_inode_used() failure
- ext4_iget() failure
Fix this by introducing an 'out_brelse' label placed just before
the existing 'out' label to ensure iloc.bh is always released.
Additionally, make ext4_fc_replay_inode() propagate errors
properly instead of always returning 0.
Reported-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Fixes: 8016e29f43 ("ext4: fast commit recovery path")
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260323060836.3452660-1-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
This commit is contained in:
parent
0c90eed1b9
commit
ec0a7500d8
|
|
@ -1613,19 +1613,21 @@ static int ext4_fc_replay_inode(struct super_block *sb,
|
|||
/* Immediately update the inode on disk. */
|
||||
ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_brelse;
|
||||
ret = sync_dirty_buffer(iloc.bh);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_brelse;
|
||||
ret = ext4_mark_inode_used(sb, ino);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_brelse;
|
||||
|
||||
/* Given that we just wrote the inode on disk, this SHOULD succeed. */
|
||||
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
|
||||
if (IS_ERR(inode)) {
|
||||
ext4_debug("Inode not found.");
|
||||
return -EFSCORRUPTED;
|
||||
inode = NULL;
|
||||
ret = -EFSCORRUPTED;
|
||||
goto out_brelse;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1642,13 +1644,14 @@ static int ext4_fc_replay_inode(struct super_block *sb,
|
|||
ext4_inode_csum_set(inode, ext4_raw_inode(&iloc), EXT4_I(inode));
|
||||
ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh);
|
||||
sync_dirty_buffer(iloc.bh);
|
||||
out_brelse:
|
||||
brelse(iloc.bh);
|
||||
out:
|
||||
iput(inode);
|
||||
if (!ret)
|
||||
blkdev_issue_flush(sb->s_bdev);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue