From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 62A1F1FF141 for ; Mon, 30 Mar 2026 13:09:42 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id D42641DBB3; Mon, 30 Mar 2026 13:10:02 +0200 (CEST) From: Fiona Ebner To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server 1/2] hotplug pending: only check if USB devices are left when one was unplugged Date: Mon, 30 Mar 2026 13:09:43 +0200 Message-ID: <20260330110954.82174-2-f.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260330110954.82174-1-f.ebner@proxmox.com> References: <20260330110954.82174-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1774868943372 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.005 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: ZUWF7GRKTG4MVV5RHPAXJBDQY3CU63M6 X-Message-ID-Hash: ZUWF7GRKTG4MVV5RHPAXJBDQY3CU63M6 X-MailFrom: f.ebner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The call to unplug the 'xhci' controller would happen each time as part of the vmconfig_hotplug_pending() call as long as the VM did not have any USB devices and as long as it had a new enough version to support USB hotplug, even if the actual changes have nothing to do with USB. Only check if there are any USB devices left if one was unplugged. In particular, this avoid issuing superfluous QMP commands (via vm_devices_list()) to check for the presence of the 'xhci' controller for unrelated changes. Previously, if an 'xhci' was added as part of a failing USB hotplug in qemu_usb_hotplug(), it would be removed again implicitly by the check at the end of vmconfig_hotplug_pending() that is now guarded. Add explicitly error handling to remove the added 'xhci' controller again in the error handling case in qemu_usb_hotplug() to avoid a left-over. Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 5acd1ac8..26560122 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -4245,15 +4245,26 @@ sub qemu_usb_hotplug { vm_deviceunplug($vmid, $conf, $deviceid); # check if xhci controller is necessary and available + my $added_xhci; my $devicelist = vm_devices_list($vmid); if (!$devicelist->{xhci}) { my $pciaddr = print_pci_addr("xhci", undef, $arch); qemu_deviceadd($vmid, PVE::QemuServer::USB::print_qemu_xhci_controller($pciaddr)); + $added_xhci = 1; } # add the new one - vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type); + eval { vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type); }; + if (my $err = $@) { + if ($added_xhci) { + eval { vm_deviceunplug($vmid, $conf, 'xhci'); }; + warn "failed to unplug xhci controller - $@" if $@; + } + die $err; + } + + return; } sub qemu_cpu_hotplug { @@ -4650,6 +4661,7 @@ sub vmconfig_hotplug_pending { my $version = extract_version($machine_type, get_running_qemu_version($vmid)); my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1'); + my $usb_was_unplugged = 0; my $usb_hotplug = $hotplug_features->{usb} && min_version($version, 7, 1) @@ -4680,6 +4692,7 @@ sub vmconfig_hotplug_pending { die "skip\n" if !$usb_hotplug; vm_deviceunplug($vmid, $conf, "usbredirdev$index"); # if it's a spice port vm_deviceunplug($vmid, $conf, $opt); + $usb_was_unplugged = 1; } elsif ($opt eq 'vcpus') { die "skip\n" if !$hotplug_features->{cpu}; qemu_cpu_hotplug($vmid, $conf, undef); @@ -4852,7 +4865,7 @@ sub vmconfig_hotplug_pending { } # unplug xhci controller if no usb device is left - if ($usb_hotplug) { + if ($usb_was_unplugged) { my $has_usb = 0; for (my $i = 0; $i < $PVE::QemuServer::USB::MAX_USB_DEVICES; $i++) { next if !defined($conf->{"usb$i"}); -- 2.47.3