mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
btrfs: fix the possible bioc_list memory leak during error
There are two possible ways to leak bioc memory on
btrfs_ordered_extent::bioc_list:
- An error occurred for btrfs_insert_one_raid_extent()
Then the function btrfs_insert_raid_extent() immediately return
without freeing any bioc in the bioc_list.
- An ordered extent hit an IO error
In that case the ordered extent will have BTRFS_ORDERED_IOERR set, and
skip the call on btrfs_insert_raid_extent() completely.
Fix the problem by:
- Introduce a new helper, btrfs_cleanup_ordered_bioc_list()
Which will remove all bioc from the bioc_list, and release the bioc.
- Call the above helper for btrfs_insert_raid_extent()
So that the cleanup helper is always called no matter what.
- Call the above helper for btrfs_finish_one_ordered()
This is called just before the final release on the ordered extent.
This was reported by Sashiko when reviewing another patch.
Link: https://sashiko.dev/#/patchset/20260817021512.3010812-1-shuangpeng.kernel%40gmail.com
Fixes: 02c372e1f0 ("btrfs: add support for inserting raid stripe extents")
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
a8813a923f
commit
afbe737783
|
|
@ -3436,6 +3436,9 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent)
|
|||
*/
|
||||
btrfs_remove_ordered_extent(ordered_extent);
|
||||
|
||||
/* Cleanup any remaining biocs attached to the OE. */
|
||||
btrfs_cleanup_ordered_bioc_list(ordered_extent);
|
||||
|
||||
/* once for us */
|
||||
btrfs_put_ordered_extent(ordered_extent);
|
||||
/* once for the tree */
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
|
|||
struct btrfs_ordered_extent *ordered_extent)
|
||||
{
|
||||
struct btrfs_io_context *bioc;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
|
||||
return 0;
|
||||
|
|
@ -381,17 +381,23 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
|
|||
list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
|
||||
ret = btrfs_insert_one_raid_extent(trans, bioc);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
while (!list_empty(&ordered_extent->bioc_list)) {
|
||||
bioc = list_first_entry(&ordered_extent->bioc_list,
|
||||
btrfs_cleanup_ordered_bioc_list(ordered_extent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered)
|
||||
{
|
||||
while (!list_empty(&ordered->bioc_list)) {
|
||||
struct btrfs_io_context *bioc;
|
||||
|
||||
bioc = list_first_entry(&ordered->bioc_list,
|
||||
typeof(*bioc), rst_ordered_entry);
|
||||
list_del(&bioc->rst_ordered_entry);
|
||||
btrfs_put_bioc(bioc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
|
|||
u32 stripe_index, struct btrfs_io_stripe *stripe);
|
||||
int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_ordered_extent *ordered_extent);
|
||||
void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered);
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||
int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user