* [PATCH] btrfs: free unlinked replace target on initialization failure
@ 2026-08-08 4:42 Guanghui Yang
2026-08-08 5:18 ` Qu Wenruo
0 siblings, 1 reply; 5+ messages in thread
From: Guanghui Yang @ 2026-08-08 4:42 UTC (permalink / raw)
To: Chris Mason, David Sterba; +Cc: linux-btrfs, linux-kernel, Guanghui Yang
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.
Signed-off-by: Guanghui Yang <3497809730@qq.com>
---
fs/btrfs/dev-replace.c | 4 ++++
fs/btrfs/volumes.c | 2 +-
fs/btrfs/volumes.h | 1 +
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 318ddb790..3c17481c9 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -240,6 +240,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
struct block_device *bdev;
u64 devid = BTRFS_DEV_REPLACE_DEVID;
int ret = 0;
+ bool device_allocated = false;
*device_out = NULL;
if (srcdev->fs_devices->seeding) {
@@ -287,6 +288,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
ret = PTR_ERR(device);
goto error;
}
+ device_allocated = true;
ret = lookup_bdev(device_path, &device->devt);
if (ret)
@@ -327,6 +329,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
return 0;
error:
+ if (device_allocated)
+ btrfs_free_device(device);
bdev_fput(bdev_file);
return ret;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a8e27db8e..c479f268a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -402,7 +402,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));
/*
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index eaf23c0dc..ecab3ce3c 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -795,6 +795,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
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);
+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);
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] btrfs: free unlinked replace target on initialization failure
2026-08-08 4:42 [PATCH] btrfs: free unlinked replace target on initialization failure Guanghui Yang
@ 2026-08-08 5:18 ` Qu Wenruo
2026-08-08 5:50 ` Guanghui Yang
2026-08-08 6:13 ` [PATCH v2] " Guanghui Yang
0 siblings, 2 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-08-08 5:18 UTC (permalink / raw)
To: Guanghui Yang, Chris Mason, David Sterba; +Cc: linux-btrfs, linux-kernel
在 2026/8/8 14:12, Guanghui Yang 写道:
> 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.
>
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
I have a very strong feeling that you're using LLM hunting down bugs.
In that case, be responsible and disclose the usage of LLM.
> ---
> fs/btrfs/dev-replace.c | 4 ++++
> fs/btrfs/volumes.c | 2 +-
> fs/btrfs/volumes.h | 1 +
> 3 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
> index 318ddb790..3c17481c9 100644
> --- a/fs/btrfs/dev-replace.c
> +++ b/fs/btrfs/dev-replace.c
> @@ -240,6 +240,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
> struct block_device *bdev;
> u64 devid = BTRFS_DEV_REPLACE_DEVID;
> int ret = 0;
> + bool device_allocated = false;
You can just initialize @device to NULL, and use that pointer to
determine if the device is properly allocated.
>
> *device_out = NULL;
> if (srcdev->fs_devices->seeding) {
> @@ -287,6 +288,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
> ret = PTR_ERR(device);
> goto error;
> }
> + device_allocated = true;
>
> ret = lookup_bdev(device_path, &device->devt);
> if (ret)
> @@ -327,6 +329,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
> return 0;
>
> error:
> + if (device_allocated)
> + btrfs_free_device(device);
> bdev_fput(bdev_file);
> return ret;
> }
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index a8e27db8e..c479f268a 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -402,7 +402,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));
> /*
> diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
> index eaf23c0dc..ecab3ce3c 100644
> --- a/fs/btrfs/volumes.h
> +++ b/fs/btrfs/volumes.h
> @@ -795,6 +795,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
> 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);
> +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);
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] btrfs: free unlinked replace target on initialization failure
2026-08-08 5:18 ` Qu Wenruo
@ 2026-08-08 5:50 ` Guanghui Yang
2026-08-08 6:13 ` [PATCH v2] " Guanghui Yang
1 sibling, 0 replies; 5+ messages in thread
From: Guanghui Yang @ 2026-08-08 5:50 UTC (permalink / raw)
To: Qu Wenruo
Cc: Chris Mason, David Sterba, linux-btrfs, linux-kernel, Guanghui Yang
Resending as plain text; my previous reply was rejected by vger because
it contained an HTML part.
Yes, I used OpenAI Codex (GPT-5) to help inspect the analyzer findings,
review the failure path, draft the change and changelog, and prepare the
test procedure. I reviewed the resulting code and ran targeted
failure-injection testing on v6.14. The patch branch also passed
make -j2 fs/btrfs/.
I should have disclosed this in the patch. Sorry for the omission. I will
add:
Assisted-by: Codex:gpt-5
to v2.
Agreed about initializing device to NULL. Checking the pointer on the
error path is simpler than adding a separate boolean. I will update that
in v2.
Thanks,
Guanghui
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] btrfs: free unlinked replace target on initialization failure
2026-08-08 5:18 ` Qu Wenruo
2026-08-08 5:50 ` Guanghui Yang
@ 2026-08-08 6:13 ` Guanghui Yang
2026-08-08 9:13 ` Qu Wenruo
1 sibling, 1 reply; 5+ messages in thread
From: Guanghui Yang @ 2026-08-08 6:13 UTC (permalink / raw)
To: Qu Wenruo
Cc: Chris Mason, David Sterba, linux-btrfs, linux-kernel, Guanghui Yang
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
Signed-off-by: Guanghui Yang <3497809730@qq.com>
---
fs/btrfs/dev-replace.c | 10 +++++++---
fs/btrfs/volumes.c | 2 +-
fs/btrfs/volumes.h | 1 +
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 318ddb790..3762429b5 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -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;
}
@@ -327,6 +329,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
return 0;
error:
+ if (device)
+ btrfs_free_device(device);
bdev_fput(bdev_file);
return ret;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a8e27db8e..c479f268a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -402,7 +402,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));
/*
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index eaf23c0dc..ecab3ce3c 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -795,6 +795,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
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);
+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);
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] btrfs: free unlinked replace target on initialization failure
2026-08-08 6:13 ` [PATCH v2] " Guanghui Yang
@ 2026-08-08 9:13 ` Qu Wenruo
0 siblings, 0 replies; 5+ messages in thread
From: Qu Wenruo @ 2026-08-08 9:13 UTC (permalink / raw)
To: Guanghui Yang; +Cc: Chris Mason, David Sterba, linux-btrfs, linux-kernel
在 2026/8/8 15:43, Guanghui Yang 写道:
> 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
> Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Pushed to for-next branch.
> ---
> fs/btrfs/dev-replace.c | 10 +++++++---
> fs/btrfs/volumes.c | 2 +-
> fs/btrfs/volumes.h | 1 +
> 3 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
> index 318ddb790..3762429b5 100644
> --- a/fs/btrfs/dev-replace.c
> +++ b/fs/btrfs/dev-replace.c
> @@ -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;
> }
>
> @@ -327,6 +329,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
> return 0;
>
> error:
> + if (device)
> + btrfs_free_device(device);
> bdev_fput(bdev_file);
> return ret;
> }
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index a8e27db8e..c479f268a 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -402,7 +402,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));
> /*
> diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
> index eaf23c0dc..ecab3ce3c 100644
> --- a/fs/btrfs/volumes.h
> +++ b/fs/btrfs/volumes.h
> @@ -795,6 +795,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
> 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);
> +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);
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-08 9:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-08 4:42 [PATCH] btrfs: free unlinked replace target on initialization failure Guanghui Yang
2026-08-08 5:18 ` Qu Wenruo
2026-08-08 5:50 ` Guanghui Yang
2026-08-08 6:13 ` [PATCH v2] " Guanghui Yang
2026-08-08 9:13 ` Qu Wenruo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®