mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
btrfs: free unlinked replace target on initialization failure
btrfs_init_dev_replace_tgtdev() allocates the replacement target before looking up its dev_t and initializing its zoned device information. If either lookup_bdev() or btrfs_get_dev_zone_info() fails, the device has not been linked into fs_devices->devices yet, but the error path only drops the block device file reference. Free the allocated device on this error path to release its name, allocation state, zone info, and the device itself. The issue was found by a failure-path metadata residual analyzer and verified with targeted failure injection on v6.14. Assisted-by: Codex:gpt-5 Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Guanghui Yang <3497809730@qq.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
24a19b953e
commit
12aeb0dc64
|
|
@ -235,7 +235,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||
struct btrfs_device **device_out)
|
||||
{
|
||||
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
|
||||
struct btrfs_device *device;
|
||||
struct btrfs_device *device = NULL;
|
||||
struct btrfs_device *tmp_device;
|
||||
struct file *bdev_file;
|
||||
struct block_device *bdev;
|
||||
u64 devid = BTRFS_DEV_REPLACE_DEVID;
|
||||
|
|
@ -264,8 +265,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||
|
||||
sync_blockdev(bdev);
|
||||
|
||||
list_for_each_entry(device, &fs_devices->devices, dev_list) {
|
||||
if (device->bdev == bdev) {
|
||||
list_for_each_entry(tmp_device, &fs_devices->devices, dev_list) {
|
||||
if (tmp_device->bdev == bdev) {
|
||||
btrfs_err(fs_info,
|
||||
"target device is in the filesystem!");
|
||||
ret = -EEXIST;
|
||||
|
|
@ -285,6 +286,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||
device = btrfs_alloc_device(NULL, &devid, NULL, device_path);
|
||||
if (IS_ERR(device)) {
|
||||
ret = PTR_ERR(device);
|
||||
device = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -328,6 +330,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||
|
||||
error:
|
||||
/* Undo the open-time freeze deny. */
|
||||
if (device)
|
||||
btrfs_free_device(device);
|
||||
btrfs_release_device_allow_freeze(bdev_file);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
|
|||
return fs_devs;
|
||||
}
|
||||
|
||||
static void btrfs_free_device(struct btrfs_device *device)
|
||||
void btrfs_free_device(struct btrfs_device *device)
|
||||
{
|
||||
WARN_ON(!list_empty(&device->post_commit_list));
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -799,6 +799,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev);
|
|||
void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev);
|
||||
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev,
|
||||
bool allow_freeze);
|
||||
void btrfs_free_device(struct btrfs_device *device);
|
||||
unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
|
||||
u64 logical);
|
||||
u64 btrfs_calc_stripe_length(const struct btrfs_chunk_map *map);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user