* [PATCH qemu-server v2] fix #7705: blockdev: detach backing chain on disk move/hot-unplug
@ 2026-06-17 12:12 Arthur Bied-Charreton
2026-06-18 7:25 ` Jakob Klocker
0 siblings, 1 reply; 2+ messages in thread
From: Arthur Bied-Charreton @ 2026-06-17 12:12 UTC (permalink / raw)
To: pve-devel
When snapshots-as-volume-chains is enabled, moving or hot-unplugging a
disk that holds snapshots does not detach the snapshot volumes.
`Blockdev::detach` is called in both paths and only follows the `file`
child, so the snapshot nodes are left behind. Since they were added
explicitly via blockdev-add, they are also not GCed by QEMU and, as a
result, keep their source volumes open.
Deleting one of those snapshots after the move does not detach the
orphaned block node because the disk is no longer attached to the
running VM. QEMU keeps the volume open for as long as the VM runs, and a
later attempt to remove the source fails with lvremove reporting the LV
as still in use.
Add 'follow-backing' option to `Blockdev::detach`. When enabled, the
'backing' children are detached in addition to the 'file' children,
meaning the snapshot blockdevs are released.
Enable 'follow-backing' at the following callsites:
* qemu_handle_concluded_blockjob (on complete the source is detached
along with the backing snapshot chain, on cancel/error it detaches the
mirror target, which is flat so follow-backing is a no-op)
* qemu_drivedel
Signed-off-by: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
---
Changes since v1:
- Update `Blockdev::detach`'s POD.
src/PVE/QemuServer.pm | 6 +++++-
src/PVE/QemuServer/BlockJob.pm | 4 +++-
src/PVE/QemuServer/Blockdev.pm | 26 ++++++++++++++++++++------
3 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm
index 55e9f520..472bee7e 100644
--- a/src/PVE/QemuServer.pm
+++ b/src/PVE/QemuServer.pm
@@ -4082,7 +4082,11 @@ sub qemu_drivedel {
# for the switch to -blockdev
if (PVE::QemuServer::Machine::is_machine_version_at_least($machine_type, 10, 0)) {
- PVE::QemuServer::Blockdev::detach(vm_qmp_peer($vmid), "drive-$deviceid");
+ PVE::QemuServer::Blockdev::detach(
+ vm_qmp_peer($vmid),
+ "drive-$deviceid",
+ { 'follow-backing' => 1 },
+ );
return 1;
} else {
my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid", 10 * 60);
diff --git a/src/PVE/QemuServer/BlockJob.pm b/src/PVE/QemuServer/BlockJob.pm
index 921f046c..493dda33 100644
--- a/src/PVE/QemuServer/BlockJob.pm
+++ b/src/PVE/QemuServer/BlockJob.pm
@@ -34,7 +34,9 @@ sub qemu_handle_concluded_blockjob {
$job->{'detach-node-name'} = $job->{'target-node-name'} if $qmp_info->{error} || $job->{cancel};
if (my $node_name = $job->{'detach-node-name'}) {
- eval { PVE::QemuServer::Blockdev::detach($qmp_peer, $node_name); };
+ eval {
+ PVE::QemuServer::Blockdev::detach($qmp_peer, $node_name, { 'follow-backing' => 1 });
+ };
log_warn($@) if $@;
}
diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm
index 101c747c..8eafb9fb 100644
--- a/src/PVE/QemuServer/Blockdev.pm
+++ b/src/PVE/QemuServer/Blockdev.pm
@@ -637,7 +637,7 @@ sub attach {
=head3 detach
- detach($qmp_peer, $node_name);
+ detach($qmp_peer, $node_name, $opts);
Detach the block device C<$node_name> from the QMP peer C<$qmp_peer>. Also removes associated child
block nodes.
@@ -650,15 +650,25 @@ Parameters:
=item C<$node_name>: The node name identifying the block node in QEMU.
+=item C<$opts> Additional options. Possible values:
+
+=over
+
+=item C<'follow-backing'>: also detach the 'backing' children
+
+=back
+
=back
=cut
sub detach {
- my ($qmp_peer, $node_name) = @_;
+ my ($qmp_peer, $node_name, $opts) = @_;
die "Blockdev::detach - no node name\n" if !$node_name;
+ my $follow_backing = $opts->{'follow-backing'};
+
my $block_info = qmp_cmd($qmp_peer, "query-named-block-nodes");
$block_info = { map { $_->{'node-name'} => $_ } $block_info->@* };
@@ -667,12 +677,13 @@ sub detach {
$remove_throttle_group_id = throttle_group_id($drive_id);
}
- while ($node_name) {
- last if !$block_info->{$node_name}; # already gone
+ my @queue = ($node_name);
+ while (defined(my $node_name = shift @queue)) {
+ next if !$block_info->{$node_name}; # already gone
my $res = qmp_cmd($qmp_peer, 'blockdev-del', 'node-name' => "$node_name", noerr => 1);
if (my $err = $res->{error}) {
- last if $err =~ m/Failed to find node with node-name/; # already gone
+ next if $err =~ m/Failed to find node with node-name/; # already gone
die "deleting blockdev '$node_name' failed : $err\n";
}
@@ -680,7 +691,10 @@ sub detach {
# Recursively remove 'file' child nodes. QEMU will auto-remove implicitly added child nodes,
# but e.g. the child of the top throttle node might have been explicitly added as a mirror
# target, and needs to be removed manually.
- $node_name = $children->{file}->{'node-name'};
+ # 'backing' is only followed when requested, because callers tearing down a single chain node
+ # rely on the nodes below it surviving.
+ push @queue, $children->{file}->{'node-name'} if $children->{file};
+ push @queue, $children->{backing}->{'node-name'} if $follow_backing && $children->{backing};
}
if ($remove_throttle_group_id) {
--
2.47.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH qemu-server v2] fix #7705: blockdev: detach backing chain on disk move/hot-unplug
2026-06-17 12:12 [PATCH qemu-server v2] fix #7705: blockdev: detach backing chain on disk move/hot-unplug Arthur Bied-Charreton
@ 2026-06-18 7:25 ` Jakob Klocker
0 siblings, 0 replies; 2+ messages in thread
From: Jakob Klocker @ 2026-06-18 7:25 UTC (permalink / raw)
To: Arthur Bied-Charreton, pve-devel
I've tested the reproducer [0] both with and without the patch applied.
Without the patch, lvremove failed because the source LV was still in
use. I confirmed that the corresponding block node remained attached
by checking QEMU's info block output.
With the patch applied, lvremove completed successfully and I could no
longer reproduce the issue.
Consider this:
Tested-by: Jakob Klocker <j.klocker@proxmox.com>
[0] https://bugzilla.proxmox.com/show_bug.cgi?id=7705#c0
On 6/17/26 2:13 PM, Arthur Bied-Charreton wrote:
> When snapshots-as-volume-chains is enabled, moving or hot-unplugging a
> disk that holds snapshots does not detach the snapshot volumes.
> [...]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-18 7:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 12:12 [PATCH qemu-server v2] fix #7705: blockdev: detach backing chain on disk move/hot-unplug Arthur Bied-Charreton
2026-06-18 7:25 ` Jakob Klocker
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.