mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
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>
62 lines
1.7 KiB
C
62 lines
1.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2023 Western Digital Corporation or its affiliates.
|
|
*/
|
|
|
|
#ifndef BTRFS_RAID_STRIPE_TREE_H
|
|
#define BTRFS_RAID_STRIPE_TREE_H
|
|
|
|
#include <linux/types.h>
|
|
#include <uapi/linux/btrfs_tree.h>
|
|
#include "fs.h"
|
|
#include "accessors.h"
|
|
|
|
#define BTRFS_RST_SUPP_BLOCK_GROUP_MASK (BTRFS_BLOCK_GROUP_DUP | \
|
|
BTRFS_BLOCK_GROUP_RAID1_MASK | \
|
|
BTRFS_BLOCK_GROUP_RAID0 | \
|
|
BTRFS_BLOCK_GROUP_RAID10)
|
|
|
|
struct btrfs_io_context;
|
|
struct btrfs_io_stripe;
|
|
struct btrfs_fs_info;
|
|
struct btrfs_ordered_extent;
|
|
struct btrfs_trans_handle;
|
|
|
|
int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 length);
|
|
int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
|
|
u64 logical, u64 *length, u64 map_type,
|
|
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,
|
|
struct btrfs_io_context *bioc);
|
|
#endif
|
|
|
|
static inline bool btrfs_need_stripe_tree_update(struct btrfs_fs_info *fs_info,
|
|
u64 map_type)
|
|
{
|
|
u64 type = map_type & BTRFS_BLOCK_GROUP_TYPE_MASK;
|
|
u64 profile = map_type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
|
|
|
|
if (!btrfs_fs_incompat(fs_info, RAID_STRIPE_TREE))
|
|
return false;
|
|
|
|
if (type != BTRFS_BLOCK_GROUP_DATA)
|
|
return false;
|
|
|
|
if (profile & BTRFS_RST_SUPP_BLOCK_GROUP_MASK)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static inline int btrfs_num_raid_stripes(u32 item_size)
|
|
{
|
|
return item_size / sizeof(struct btrfs_raid_stride);
|
|
}
|
|
|
|
#endif
|