From 9e4210a025d56f90045fd4115c7f436303ee778b Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 11 Aug 2025 12:47:12 +0200 Subject: [PATCH 01/79] machine: add extract_version_parts helper Note that the regex is changed to not include the '+pve' part. No functional change intended. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250811104812.189393-2-f.ebner@proxmox.com --- src/PVE/QemuServer/Machine.pm | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/PVE/QemuServer/Machine.pm b/src/PVE/QemuServer/Machine.pm index b2bac932..3d98ee0b 100644 --- a/src/PVE/QemuServer/Machine.pm +++ b/src/PVE/QemuServer/Machine.pm @@ -156,19 +156,37 @@ sub get_current_qemu_machine { return current_from_query_machines($res); } +=head3 extract_version_parts + + my ($major, $minor, $pve) = extract_version_parts($machine_type); + +Returns the major, minor and pve versions from the given C<$machine_type> string. Returns nothing if +the string did not contain any version or if parsing failed. + +=cut + +my sub extract_version_parts { + my ($machine_type) = @_; + + if ($machine_type =~ + m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(?:\+pve(\d+))?(?:\.pxe)?/ + ) { + return ($1, $2, $4); + } + return; +} + # returns a string with major.minor+pve, patch version-part is ignored # as it's seldom resembling a real QEMU machine type, so it would be '0' 99% of # the time anyway.. This explicitly separates pveversion from the machine. sub extract_version { my ($machine_type, $kvmversion) = @_; - if ( - defined($machine_type) - && $machine_type =~ - m/^(?:pc(?:-i440fx|-q35)?|virt)-(\d+)\.(\d+)(?:\.(\d+))?(\+pve\d+)?(?:\.pxe)?/ - ) { - my $versionstr = "$1.$2"; - $versionstr .= $4 if $4; + my ($major, $minor, $pve); + ($major, $minor, $pve) = extract_version_parts($machine_type) if defined($machine_type); + if (defined($major) && defined($minor)) { + my $versionstr = "${major}.${minor}"; + $versionstr .= "+pve${pve}" if $pve; return $versionstr; } elsif (defined($kvmversion)) { if ($kvmversion =~ m/^(\d+)\.(\d+)/) { From 240f44a369fb6efeb6b8599896f87baf5be6274c Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 11 Aug 2025 12:47:13 +0200 Subject: [PATCH 02/79] fix #6648: api: machine versions: fix ordering It's necessary to numerically compare versions in machine types, so introduce a new helper which does that. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250811104812.189393-3-f.ebner@proxmox.com --- src/PVE/API2/Qemu/Machine.pm | 6 +++++- src/PVE/QemuServer/Machine.pm | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu/Machine.pm b/src/PVE/API2/Qemu/Machine.pm index 41281af2..0fc1ea6c 100644 --- a/src/PVE/API2/Qemu/Machine.pm +++ b/src/PVE/API2/Qemu/Machine.pm @@ -81,7 +81,11 @@ __PACKAGE__->register_method({ } } - return [sort { $b->{id} cmp $a->{id} } ($machines->@*, $pve_machines->@*)]; # merge & sort + return [ + sort { + PVE::QemuServer::Machine::machine_version_cmp($b->{id}, $a->{id}) + } ($machines->@*, $pve_machines->@*) + ]; # merge & sort }; die "could not load supported machine versions - $@\n" if $@; return $supported_machine_list; diff --git a/src/PVE/QemuServer/Machine.pm b/src/PVE/QemuServer/Machine.pm index 3d98ee0b..9d17344a 100644 --- a/src/PVE/QemuServer/Machine.pm +++ b/src/PVE/QemuServer/Machine.pm @@ -198,6 +198,30 @@ sub extract_version { return; } +=head3 machine_version_cmp + + sort { machine_version_cmp($a, $b) } @machine_types + +Comparision function for sorting machine types by version. + +=cut + +sub machine_version_cmp { + my ($machine_type_a, $machine_type_b) = @_; + + my ($major_a, $minor_a, $pve_a) = extract_version_parts($machine_type_a); + my ($major_b, $minor_b, $pve_b) = extract_version_parts($machine_type_b); + + return PVE::QemuServer::Helpers::version_cmp( + $major_a, + $major_b, + $minor_a, + $minor_b, + $pve_a, + $pve_b, + ); +} + sub is_machine_version_at_least { my ($machine_type, $major, $minor, $pve) = @_; From 1441c009bc945533e2ec1d51a2623d4159a81aaa Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 11 Aug 2025 15:51:33 +0200 Subject: [PATCH 03/79] print drive commandline: prohibit using snapshot-as-volume-chain qcow2 images Require that snapshot-as-volume-chain qcow2 images are always used in combination with '-blockdev', rather than '-drive'. With '-drive', the 'discard-no-unref' option is not set and the fragmentation can lead to the same issue that for '-blockdev', was solved by commit a3a9a2ab ("fix #6543: use qcow2 'discard-no-unref' option when using snapshot-as-volume-chain"). While it would be possible to set the flag for '-drive' too, the snapshot-as-volume-chain feature already only works with machine type >= 10.0, see commit 6b2b45fd ("snapshot create/delete: die early for snapshot-as-volume-chain for pre-10.0 machine version") and it's only tested for those. Avoid accidents and other unknown issues by being strict and prohibiting usage without '-blockdev'. Reported-by: Friedrich Weber Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250811135154.253817-1-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index e30b27cb..cfc54568 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1335,6 +1335,13 @@ sub print_drive_commandline_full { my ($path, $format) = PVE::QemuServer::Drive::get_path_and_format($storecfg, $drive, $live_restore_name); + if ($scfg && $scfg->{'snapshot-as-volume-chain'} && $format && $format eq 'qcow2') { + # the print_drive_commandline_full() function is only used if machine version is < 10.0 + die "storage for '$drive->{file}' is configured for snapshots as a volume chain - this" + . " requires QEMU machine version >= 10.0. See" + . " https://pve.proxmox.com/wiki/QEMU_Machine_Version_Upgrade\n"; + } + my $is_rbd = $path =~ m/^rbd:/; my $opts = ''; From 9e973210eaba91fc7a3f8d9ef5b796bcf12e3e38 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 13:56:29 +0200 Subject: [PATCH 04/79] qmp client: add $noerr argument Using the $noerr argument will allow callers to opt-in to handling errors themselves. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812115652.79330-2-f.ebner@proxmox.com --- src/PVE/QMPClient.pm | 8 ++++--- src/PVE/QemuServer/Monitor.pm | 40 ++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/PVE/QMPClient.pm b/src/PVE/QMPClient.pm index 87d61144..7b19be9d 100644 --- a/src/PVE/QMPClient.pm +++ b/src/PVE/QMPClient.pm @@ -86,7 +86,7 @@ sub queue_cmd { # execute a single command sub cmd { - my ($self, $vmid, $cmd, $timeout) = @_; + my ($self, $vmid, $cmd, $timeout, $noerr) = @_; my $result; @@ -155,8 +155,10 @@ sub cmd { $self->queue_execute($timeout, 2); - die "VM $vmid qmp command '$cmd->{execute}' failed - $queue_info->{error}" - if defined($queue_info->{error}); + if (defined($queue_info->{error})) { + die "VM $vmid qmp command '$cmd->{execute}' failed - $queue_info->{error}" if !$noerr; + $result = { error => $queue_info->{error} }; + } return $result; } diff --git a/src/PVE/QemuServer/Monitor.pm b/src/PVE/QemuServer/Monitor.pm index 5956e1c4..062e71be 100644 --- a/src/PVE/QemuServer/Monitor.pm +++ b/src/PVE/QemuServer/Monitor.pm @@ -12,14 +12,48 @@ our @EXPORT_OK = qw( mon_cmd ); +=head3 qmp_cmd + + my $cmd = { execute => $qmp_command_name, arguments => \%params }; + my $result = qmp_cmd($vmid, $cmd); + +Execute the C<$qmp_command_name> with arguments C<%params> for VM C<$vmid>. Dies if the VM is not +running or the monitor socket cannot be reached, even if the C argument is used. Returns the +structured result from the QMP side converted from JSON to structured Perl data. In case the +C argument is used and the QMP command failed or timed out, the result is a hash reference +with an C key containing the error message. + +Parameters: + +=over + +=item C<$vmid>: The ID of the virtual machine. + +=item C<$cmd>: Hash reference containing the QMP command name for the C key and additional +arguments for the QMP command under the C key. The following custom arguments are not +part of the QMP schema and supported for all commands: + +=over + +=item C: wait at most for this amount of time. If there was no actual error, the QMP/QGA +command will still continue to be executed even after the timeout reached. + +=item C: do not die when the command gets an error or the timeout is hit. The caller needs to +handle the error that is returned as a structured result. + +=back + +=back + +=cut sub qmp_cmd { my ($vmid, $cmd) = @_; my $res; - my $timeout; + my ($noerr, $timeout); if ($cmd->{arguments}) { - $timeout = delete $cmd->{arguments}->{timeout}; + ($noerr, $timeout) = delete($cmd->{arguments}->@{qw(noerr timeout)}); } eval { @@ -28,7 +62,7 @@ sub qmp_cmd { if (-e $sname) { # test if VM is reasonably new and supports qmp/qga my $qmpclient = PVE::QMPClient->new(); - $res = $qmpclient->cmd($vmid, $cmd, $timeout); + $res = $qmpclient->cmd($vmid, $cmd, $timeout, $noerr); } else { die "unable to open monitor socket\n"; } From d2f055b03a1acc69296a04d8514acc6256ce33fa Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 13:56:30 +0200 Subject: [PATCH 05/79] blockdev: attach/detach: silence errors for QMP commands for which failure may be expected Without passing 'noerr' to mon_cmd(), errors are logged to the system journal. In attach() and detach(), there are two mon_cmd() calls that are expected to fail in some scenarios for which the errors should not be logged. Reported-by: Friedrich Weber Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812115652.79330-3-f.ebner@proxmox.com --- src/PVE/QemuServer/Blockdev.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index d0d7e684..04eeed3c 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -575,7 +575,7 @@ sub attach { eval { if ($throttle_group_id) { # Try to remove potential left-over. - eval { mon_cmd($vmid, 'object-del', id => $throttle_group_id); }; + mon_cmd($vmid, 'object-del', id => $throttle_group_id, noerr => 1); my $throttle_group = generate_throttle_group($drive); mon_cmd($vmid, 'object-add', $throttle_group->%*); @@ -630,8 +630,8 @@ sub detach { while ($node_name) { last if !$block_info->{$node_name}; # already gone - eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => "$node_name"); }; - if (my $err = $@) { + my $res = mon_cmd($vmid, '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 die "deleting blockdev '$node_name' failed : $err\n"; } From e7cf7c0056f8fe7dc4487d3465a4ba27e9289190 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 13:56:31 +0200 Subject: [PATCH 06/79] blockdev: delete/replace: re-use detach() helper Re-using the detach() helper has the side effect of avoiding logging errors to syslog for automatically removed child nodes. This should be the case for all file nodes here. None are explicitly added via blockdev-add and thus QEMU already auto-removes them. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812115652.79330-4-f.ebner@proxmox.com --- src/PVE/QemuServer/Blockdev.pm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 04eeed3c..f5798cbf 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -873,9 +873,8 @@ sub blockdev_external_snapshot { sub blockdev_delete { my ($storecfg, $vmid, $drive, $file_blockdev, $fmt_blockdev, $snap) = @_; - #add eval as reopen is auto removing the old nodename automatically only if it was created at vm start in command line argument - eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $fmt_blockdev->{'node-name'}) }; - eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $file_blockdev->{'node-name'}) }; + eval { detach($vmid, $fmt_blockdev->{'node-name'}); }; + warn "detaching block node for $file_blockdev->{filename} failed - $@" if $@; #delete the file (don't use vdisk_free as we don't want to delete all snapshot chain) print "delete old $file_blockdev->{filename}\n"; @@ -982,9 +981,8 @@ sub blockdev_replace { } # delete old file|fmt nodes - # add eval as reopen is auto removing the old nodename automatically only if it was created at vm start in command line argument - eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $src_fmt_blockdev_name) }; - eval { mon_cmd($vmid, 'blockdev-del', 'node-name' => $src_file_blockdev_name) }; + eval { detach($vmid, $src_fmt_blockdev_name); }; + warn "detaching block node for $src_snap failed - $@" if $@; } sub blockdev_commit { From 2746b963cf1d135df55d8bf15eb77b0685e3602d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Tue, 12 Aug 2025 15:11:27 +0200 Subject: [PATCH 07/79] bump version to 9.0.17 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fabian Grünbichler --- debian/changelog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8b63a739..4989804f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +qemu-server (9.0.17) trixie; urgency=medium + + * fix #6648: api: machine versions: fix ordering + + * prohibit using snapshot-as-volume-chain qcow2 images with pre-10.0 machines + + * qmp client: add $noerr argument + + * blockdev: attach/detach: silence errors for QMP commands for which failure may be expected + + * blockdev: delete/replace: re-use detach() helper + + -- Proxmox Support Team Tue, 12 Aug 2025 15:10:38 +0200 + qemu-server (9.0.16) trixie; urgency=medium * vmstate: always quiesce warnings on VM stop cleanup as at this point, the From ad2610f2188002a6b32f0d58299c58dcb4b16743 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:04:39 +0200 Subject: [PATCH 08/79] make tidy Signed-off-by: Fiona Ebner --- src/PVE/QemuServer/Monitor.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/QemuServer/Monitor.pm b/src/PVE/QemuServer/Monitor.pm index 062e71be..0cccdfbe 100644 --- a/src/PVE/QemuServer/Monitor.pm +++ b/src/PVE/QemuServer/Monitor.pm @@ -46,6 +46,7 @@ handle the error that is returned as a structured result. =back =cut + sub qmp_cmd { my ($vmid, $cmd) = @_; From 2f3c741bfdffc49b50e17274bc25881a41f57ff7 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 17:30:14 +0200 Subject: [PATCH 09/79] close #6378: expose guest-phys-bits CPU option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting Fabian Grünbichler from the bug report: > Intel ships some CPUs where the CPU address width and the IOMMU > address width are different, which requires setting that option to > properly support huge pages and/or VFIO: > > https://bugzilla.kernel.org/show_bug.cgi?id=220057 > https://lore.kernel.org/all/20250502224035.3183451-1-alex.williamson@redhat.com/t > https://lore.kernel.org/qemu-devel/20250130134346.1754143-1-clg@redhat.com/ This likely also gives users a way forward with a regression reported in the community forum: https://forum.proxmox.com/threads/169586/ Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812153144.154949-1-f.ebner@proxmox.com --- src/PVE/QemuServer/CPUConfig.pm | 31 +++++++++++++------ .../q35-viommu-intel-guest-phys-bits.conf | 2 ++ .../q35-viommu-intel-guest-phys-bits.conf.cmd | 25 +++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf create mode 100644 src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf.cmd diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm index 1c7c12fc..786a99d8 100644 --- a/src/PVE/QemuServer/CPUConfig.pm +++ b/src/PVE/QemuServer/CPUConfig.pm @@ -223,6 +223,13 @@ my $cpu_fmt = { pattern => qr/$cpu_flag_any_re(;$cpu_flag_any_re)*/, optional => 1, }, + 'guest-phys-bits' => { + type => 'integer', + minimum => 32, # see target/i386/cpu.c in QEMU + maximum => 64, + description => "Number of physical address bits available to the guest.", + optional => 1, + }, 'phys-bits' => { type => 'string', format => 'pve-phys-bits', @@ -680,18 +687,22 @@ sub get_cpu_options { $pve_forced_flags, ); - my $phys_bits = ''; - foreach my $conf ($custom_cpu, $cpu) { - next if !defined($conf); - my $conf_val = $conf->{'phys-bits'}; - next if !$conf_val; - if ($conf_val eq 'host') { - $phys_bits = ",host-phys-bits=true"; - } else { - $phys_bits = ",phys-bits=$conf_val"; + for my $phys_bits_opt (qw(guest-phys-bits phys-bits)) { + my $phys_bits = ''; + foreach my $conf ($custom_cpu, $cpu) { + next if !defined($conf); + my $conf_val = $conf->{$phys_bits_opt}; + next if !$conf_val; + if ($conf_val eq 'host') { + die "unexpected value 'host' for guest-phys-bits" + if $phys_bits_opt eq 'guest-phys-bits'; + $phys_bits = ",host-phys-bits=true"; + } else { + $phys_bits = ",${phys_bits_opt}=${conf_val}"; + } } + $cpu_str .= $phys_bits; } - $cpu_str .= $phys_bits; return ('-cpu', $cpu_str); } diff --git a/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf b/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf new file mode 100644 index 00000000..7decb63e --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf @@ -0,0 +1,2 @@ +machine: q35,viommu=intel +cpu: host,guest-phys-bits=39 diff --git a/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf.cmd b/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf.cmd new file mode 100644 index 00000000..b24baeb0 --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-intel-guest-phys-bits.conf.cmd @@ -0,0 +1,25 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu 'host,+kvm_pv_eoi,+kvm_pv_unhalt,guest-phys-bits=39' \ + -m 512 \ + -global 'ICH9-LPC.disable_s3=1' \ + -global 'ICH9-LPC.disable_s4=1' \ + -device 'intel-iommu,intremap=on,caching-mode=on' \ + -readconfig /usr/share/qemu-server/pve-q35-4.0.cfg \ + -device 'usb-tablet,id=tablet,bus=ehci.0,port=1' \ + -device 'VGA,id=vga,bus=pcie.0,addr=0x1' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=q35+pve0,kernel-irqchip=split' From 58b929879906a69fdf4e3a9bb2180986881ca1df Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:37:39 +0200 Subject: [PATCH 10/79] ovmf: pass along whether the VM is a template This is in preparation to remove the hidden dependency from the Drive module to QemuConfig. Note that the drive_is_read_only() can be replaced with $is_template for OVMF, because the helper only behaves differently for IDE and SATA, but not for EFI disks. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812143900.138723-2-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 3 ++- src/PVE/QemuServer/OVMF.pm | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index cfc54568..d6657a1f 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3361,8 +3361,9 @@ sub config_to_command { 'machine-version' => $machine_version, q35 => $q35, }; + my $is_template = PVE::QemuConfig->is_template($conf); my ($ovmf_cmd, $ovmf_machine_flags) = PVE::QemuServer::OVMF::print_ovmf_commandline( - $conf, $storecfg, $vmid, $hw_info, $version_guard, + $conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template, ); push $cmd->@*, $ovmf_cmd->@*; push $machineFlags->@*, $ovmf_machine_flags->@*; diff --git a/src/PVE/QemuServer/OVMF.pm b/src/PVE/QemuServer/OVMF.pm index 8948651c..72f5be0d 100644 --- a/src/PVE/QemuServer/OVMF.pm +++ b/src/PVE/QemuServer/OVMF.pm @@ -10,7 +10,7 @@ use PVE::Storage; use PVE::Tools; use PVE::QemuServer::Blockdev; -use PVE::QemuServer::Drive qw(checked_volume_format drive_is_read_only parse_drive print_drive); +use PVE::QemuServer::Drive qw(checked_volume_format parse_drive print_drive); use PVE::QemuServer::QemuImage; my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/'; @@ -79,7 +79,7 @@ my sub get_ovmf_files($$$$) { } my sub print_ovmf_drive_commandlines { - my ($conf, $storecfg, $vmid, $hw_info, $version_guard) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template) = @_; my ($amd_sev_type, $arch, $q35) = $hw_info->@{qw(amd-sev-type arch q35)}; @@ -109,7 +109,7 @@ my sub print_ovmf_drive_commandlines { $var_drive_str .= ",size=" . (-s $ovmf_vars) if $format eq 'raw' && $version_guard->(4, 1, 2); - $var_drive_str .= ',readonly=on' if drive_is_read_only($conf, $d); + $var_drive_str .= ',readonly=on' if $is_template; } else { log_warn("no efidisk configured! Using temporary efivars disk."); my $path = "/tmp/$vmid-ovmf.fd"; @@ -145,7 +145,7 @@ sub create_efidisk($$$$$$$$) { } my sub generate_ovmf_blockdev { - my ($conf, $storecfg, $vmid, $hw_info) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $is_template) = @_; my ($amd_sev_type, $arch, $machine_version, $q35) = $hw_info->@{qw(amd-sev-type arch machine-version q35)}; @@ -187,8 +187,7 @@ my sub generate_ovmf_blockdev { $drive->{cache} = 'writeback' if !$drive->{cache}; my $extra_blockdev_options = {}; - # extra protection for templates, but SATA and IDE don't support it.. - $extra_blockdev_options->{'read-only'} = 1 if drive_is_read_only($conf, $drive); + $extra_blockdev_options->{'read-only'} = 1 if $is_template; $extra_blockdev_options->{size} = -s $ovmf_vars if $format eq 'raw'; @@ -202,7 +201,7 @@ my sub generate_ovmf_blockdev { } sub print_ovmf_commandline { - my ($conf, $storecfg, $vmid, $hw_info, $version_guard) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template) = @_; my $amd_sev_type = $hw_info->{'amd-sev-type'}; @@ -217,7 +216,7 @@ sub print_ovmf_commandline { } else { if ($version_guard->(10, 0, 0)) { # for the switch to -blockdev my ($code_blockdev, $vars_blockdev, $throttle_group) = - generate_ovmf_blockdev($conf, $storecfg, $vmid, $hw_info); + generate_ovmf_blockdev($conf, $storecfg, $vmid, $hw_info, $is_template); push $cmd->@*, '-object', to_json($throttle_group, { canonical => 1 }); push $cmd->@*, '-blockdev', to_json($code_blockdev, { canonical => 1 }); @@ -225,8 +224,9 @@ sub print_ovmf_commandline { push $machine_flags->@*, "pflash0=$code_blockdev->{'node-name'}", "pflash1=$vars_blockdev->{'node-name'}"; } else { - my ($code_drive_str, $var_drive_str) = - print_ovmf_drive_commandlines($conf, $storecfg, $vmid, $hw_info, $version_guard); + my ($code_drive_str, $var_drive_str) = print_ovmf_drive_commandlines( + $conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template, + ); push $cmd->@*, '-drive', $code_drive_str; push $cmd->@*, '-drive', $var_drive_str; } From d45b08004ae2e4ea76e503d183763f083504c723 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:37:40 +0200 Subject: [PATCH 11/79] code cleanup: cfg2cmd: check if configuration is for template centrally Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812143900.138723-3-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index d6657a1f..67db9bc3 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3205,9 +3205,11 @@ sub config_to_command { my ($forcemachine, $forcecpu, $live_restore_backing, $dry_run) = $options->@{qw(force-machine force-cpu live-restore-backing dry-run)}; + my $is_template = PVE::QemuConfig->is_template($conf); + # minimize config for templates, they can only start for backup, # so most options besides the disks are irrelevant - if (PVE::QemuConfig->is_template($conf)) { + if ($is_template) { my $newconf = { template => 1, # in case below code checks that kvm => 0, # to prevent an error on hosts without virtualization extensions @@ -3361,7 +3363,6 @@ sub config_to_command { 'machine-version' => $machine_version, q35 => $q35, }; - my $is_template = PVE::QemuConfig->is_template($conf); my ($ovmf_cmd, $ovmf_machine_flags) = PVE::QemuServer::OVMF::print_ovmf_commandline( $conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template, ); @@ -3463,7 +3464,7 @@ sub config_to_command { # Add a TPM only if the VM is not a template, # to support backing up template VMs even if the TPM disk is write-protected. - add_tpm_device($vmid, $devices, $conf) if (!PVE::QemuConfig->is_template($conf)); + add_tpm_device($vmid, $devices, $conf) if !$is_template; my $sockets = 1; $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused @@ -3900,7 +3901,7 @@ sub config_to_command { print "activating and using '$vmstate' as vmstate\n"; } - if (PVE::QemuConfig->is_template($conf)) { + if ($is_template) { # needed to workaround base volumes being read-only push @$cmd, '-snapshot'; } From 69afe422e53cb0ad0aca74ba5ba20bd02933f878 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:37:41 +0200 Subject: [PATCH 12/79] fix #6675: template backup: fix regression with IDE/SATA and blockdev With ide-hd, the inserted block node needs to be marked as writable too, but -blockdev will complain if it's marked as writable but the actual backing device is read-only (e.g. read-only base LV). IDE/SATA do not support being configured as read-only, the most similar is using ide-cd instead of ide-hd, with most of the code and configuration shared in QEMU. Since a template is never actually started, the front-end device is never accessed. The backup only accesses the inserted block node, so it does not matter for the backup if the type is 'ide-cd' instead. The same issue did not manifest for '-drive', because the '-snapshot' option is used for template backups. The '-snapshot' option does not affect '-blockdev', from 'man kvm': > snapshot is incompatible with -blockdev Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812143900.138723-4-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 13 ++++++++++--- src/test/cfg2cmd/simple1-template.conf.cmd | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 67db9bc3..d3f0c589 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1272,6 +1272,15 @@ sub print_drivedevice_full { my $device_type = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd"; + # With ide-hd, the inserted block node needs to be marked as writable too, but -blockdev + # will complain if it's marked as writable but the actual backing device is read-only (e.g. + # read-only base LV). IDE/SATA do not support being configured as read-only, the most + # similar is using ide-cd instead of ide-hd, with most of the code and configuration shared + # in QEMU. Since a template is never actually started, the front-end device is never + # accessed. The backup only accesses the inserted block node, so it does not matter for the + # backup if the type is 'ide-cd' instead. + $device_type = 'cd' if $conf->{template}; + $device = "ide-$device_type"; if ($drive->{interface} eq 'ide') { $device .= ",bus=ide.$controller,unit=$unit"; @@ -3752,9 +3761,7 @@ sub config_to_command { my $extra_blockdev_options = {}; $extra_blockdev_options->{'live-restore'} = $live_restore if $live_restore; - # extra protection for templates, but SATA and IDE don't support it.. - $extra_blockdev_options->{'read-only'} = 1 - if drive_is_read_only($conf, $drive); + $extra_blockdev_options->{'read-only'} = 1 if $is_template; my $blockdev = PVE::QemuServer::Blockdev::generate_drive_blockdev( $storecfg, $drive, $machine_version, $extra_blockdev_options, diff --git a/src/test/cfg2cmd/simple1-template.conf.cmd b/src/test/cfg2cmd/simple1-template.conf.cmd index df51a4a5..369b4de9 100644 --- a/src/test/cfg2cmd/simple1-template.conf.cmd +++ b/src/test/cfg2cmd/simple1-template.conf.cmd @@ -30,7 +30,7 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/base-8006-disk-1.qcow2","node-name":"e1085774206ae4a6b6bf8426ff08f16","read-only":true},"node-name":"f1085774206ae4a6b6bf8426ff08f16","read-only":true},"node-name":"drive-scsi0","read-only":true,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,write-cache=on' \ -device 'ahci,id=ahci0,multifunction=on,bus=pci.0,addr=0x7' \ - -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/base-8006-disk-0.qcow2","node-name":"eab334c2e07734480f33dd80d89871b","read-only":false},"node-name":"fab334c2e07734480f33dd80d89871b","read-only":false},"node-name":"drive-sata0","read-only":false,"throttle-group":"throttle-drive-sata0"}' \ - -device 'ide-hd,bus=ahci0.0,drive=drive-sata0,id=sata0,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/base-8006-disk-0.qcow2","node-name":"eab334c2e07734480f33dd80d89871b","read-only":true},"node-name":"fab334c2e07734480f33dd80d89871b","read-only":true},"node-name":"drive-sata0","read-only":true,"throttle-group":"throttle-drive-sata0"}' \ + -device 'ide-cd,bus=ahci0.0,drive=drive-sata0,id=sata0,write-cache=on' \ -machine 'accel=tcg,smm=off,type=pc+pve0' \ -snapshot From bc753d2bc72f103ac39cec9699d58ae71848e316 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:37:42 +0200 Subject: [PATCH 13/79] code cleanup: drive: get rid of outdated drive_is_read_only() helper The drive_is_read_only() helper only applies to '-drive', but not '-blockdev' and is only used in a single place. Inline it to avoid accidental usages popping up in the future. This also gets rid of a hidden dependency from Drive to QemuConfig. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812143900.138723-5-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 7 ++++--- src/PVE/QemuServer/Drive.pm | 10 ---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index d3f0c589..aacdadad 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -67,7 +67,6 @@ use PVE::QemuServer::Drive qw( checked_volume_format drive_is_cloudinit drive_is_cdrom - drive_is_read_only parse_drive print_drive storage_allows_io_uring_default @@ -3778,8 +3777,10 @@ sub config_to_command { my $drive_cmd = print_drive_commandline_full($storecfg, $vmid, $drive, $live_blockdev_name); - # extra protection for templates, but SATA and IDE don't support it.. - $drive_cmd .= ',readonly=on' if drive_is_read_only($conf, $drive); + if ($is_template) { + my $interface = $drive->{interface}; + $drive_cmd .= ',readonly=on' if $interface ne 'ide' && $interface ne 'sata'; + } push @$devices, '-drive', $drive_cmd; } diff --git a/src/PVE/QemuServer/Drive.pm b/src/PVE/QemuServer/Drive.pm index 9dc4e674..79dd22e6 100644 --- a/src/PVE/QemuServer/Drive.pm +++ b/src/PVE/QemuServer/Drive.pm @@ -20,7 +20,6 @@ our @EXPORT_OK = qw( checked_volume_format drive_is_cloudinit drive_is_cdrom - drive_is_read_only parse_drive print_drive storage_allows_io_uring_default @@ -751,15 +750,6 @@ sub drive_is_cdrom { return $drive && $drive->{media} && ($drive->{media} eq 'cdrom'); } -sub drive_is_read_only { - my ($conf, $drive) = @_; - - return 0 if !PVE::QemuConfig->is_template($conf); - - # don't support being marked read-only - return $drive->{interface} ne 'sata' && $drive->{interface} ne 'ide'; -} - sub parse_drive_interface { my ($key) = @_; From 9b1460220c0a8802f3d315073e4062fe38cea137 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 12 Aug 2025 16:37:43 +0200 Subject: [PATCH 14/79] cfg2cmd: add reminder comments to remove template handling for -drive Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250812143900.138723-6-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index aacdadad..d40b14de 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3778,6 +3778,9 @@ sub config_to_command { print_drive_commandline_full($storecfg, $vmid, $drive, $live_blockdev_name); if ($is_template) { + # TODO PVE 10.x - since the temporary config for starting templates for backup + # uses the latest machine version, this should already be dead code. It's kept + # for now if for whatever reason an older QEMU build is used (e.g. bisecting). my $interface = $drive->{interface}; $drive_cmd .= ',readonly=on' if $interface ne 'ide' && $interface ne 'sata'; } @@ -3910,6 +3913,10 @@ sub config_to_command { } if ($is_template) { + # TODO PVE 10.x - since the temporary config for starting templates for backup uses the + # latest machine version, this should already be dead code. It's kept for now if for + # whatever reason an older QEMU build is used (e.g. bisecting). + # needed to workaround base volumes being read-only push @$cmd, '-snapshot'; } From 554ff732980c5de0dcfcadec2434f1ffc36e1f8a Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 13 Aug 2025 10:11:14 +0200 Subject: [PATCH 15/79] ovmf: rename 'is_template' parameter to 'readonly' to match its effect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Fabian Grünbichler Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250813081121.8569-1-f.ebner@proxmox.com --- src/PVE/QemuServer/OVMF.pm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PVE/QemuServer/OVMF.pm b/src/PVE/QemuServer/OVMF.pm index 72f5be0d..08134e30 100644 --- a/src/PVE/QemuServer/OVMF.pm +++ b/src/PVE/QemuServer/OVMF.pm @@ -79,7 +79,7 @@ my sub get_ovmf_files($$$$) { } my sub print_ovmf_drive_commandlines { - my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $readonly) = @_; my ($amd_sev_type, $arch, $q35) = $hw_info->@{qw(amd-sev-type arch q35)}; @@ -109,7 +109,7 @@ my sub print_ovmf_drive_commandlines { $var_drive_str .= ",size=" . (-s $ovmf_vars) if $format eq 'raw' && $version_guard->(4, 1, 2); - $var_drive_str .= ',readonly=on' if $is_template; + $var_drive_str .= ',readonly=on' if $readonly; } else { log_warn("no efidisk configured! Using temporary efivars disk."); my $path = "/tmp/$vmid-ovmf.fd"; @@ -145,7 +145,7 @@ sub create_efidisk($$$$$$$$) { } my sub generate_ovmf_blockdev { - my ($conf, $storecfg, $vmid, $hw_info, $is_template) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $readonly) = @_; my ($amd_sev_type, $arch, $machine_version, $q35) = $hw_info->@{qw(amd-sev-type arch machine-version q35)}; @@ -187,7 +187,7 @@ my sub generate_ovmf_blockdev { $drive->{cache} = 'writeback' if !$drive->{cache}; my $extra_blockdev_options = {}; - $extra_blockdev_options->{'read-only'} = 1 if $is_template; + $extra_blockdev_options->{'read-only'} = 1 if $readonly; $extra_blockdev_options->{size} = -s $ovmf_vars if $format eq 'raw'; @@ -201,7 +201,7 @@ my sub generate_ovmf_blockdev { } sub print_ovmf_commandline { - my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template) = @_; + my ($conf, $storecfg, $vmid, $hw_info, $version_guard, $readonly) = @_; my $amd_sev_type = $hw_info->{'amd-sev-type'}; @@ -216,7 +216,7 @@ sub print_ovmf_commandline { } else { if ($version_guard->(10, 0, 0)) { # for the switch to -blockdev my ($code_blockdev, $vars_blockdev, $throttle_group) = - generate_ovmf_blockdev($conf, $storecfg, $vmid, $hw_info, $is_template); + generate_ovmf_blockdev($conf, $storecfg, $vmid, $hw_info, $readonly); push $cmd->@*, '-object', to_json($throttle_group, { canonical => 1 }); push $cmd->@*, '-blockdev', to_json($code_blockdev, { canonical => 1 }); @@ -225,7 +225,7 @@ sub print_ovmf_commandline { "pflash1=$vars_blockdev->{'node-name'}"; } else { my ($code_drive_str, $var_drive_str) = print_ovmf_drive_commandlines( - $conf, $storecfg, $vmid, $hw_info, $version_guard, $is_template, + $conf, $storecfg, $vmid, $hw_info, $version_guard, $readonly, ); push $cmd->@*, '-drive', $code_drive_str; push $cmd->@*, '-drive', $var_drive_str; From 4a92c0415dda9d30798689aafcf8f008837c071f Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 13 Aug 2025 10:58:36 +0200 Subject: [PATCH 16/79] fix #6680: avoid setting nonexistent 'write-cache' option for scsi-{block, generic} Only scsi-cd and scsi-hd have a 'write-cache' option, scsi-block and scsi-generic do not. Setting the 'cache' setting on such a drive in the VM configuration is still valid and should not be prohibited, because it affects the blockdev settings. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250813085845.25516-2-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index d40b14de..99d4da4f 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1203,6 +1203,7 @@ sub print_drivedevice_full { my $maxdev = 0; my $machine_version = extract_version($machine_type, kvm_user_version()); + my $has_write_cache = 1; # whether the device has a 'write-cache' option my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); if ($drive->{interface} eq 'virtio') { @@ -1244,7 +1245,8 @@ sub print_drivedevice_full { } $device .= ",wwn=$drive->{wwn}" if $drive->{wwn}; - # only scsi-hd and scsi-cd support passing vendor and product information + # only scsi-hd and scsi-cd support passing vendor and product information and have a + # 'write-cache' option if ($device_type eq 'hd' || $device_type eq 'cd') { if (my $vendor = $drive->{vendor}) { $device .= ",vendor=$vendor"; @@ -1252,6 +1254,10 @@ sub print_drivedevice_full { if (my $product = $drive->{product}) { $device .= ",product=$product"; } + + $has_write_cache = 1; + } else { + $has_write_cache = 0; } } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') { @@ -1316,7 +1322,7 @@ sub print_drivedevice_full { } if (min_version($machine_version, 10, 0)) { # for the switch to -blockdev - if (!drive_is_cdrom($drive)) { + if (!drive_is_cdrom($drive) && $has_write_cache) { my $write_cache = 'on'; if (my $cache = $drive->{cache}) { $write_cache = 'off' if $cache eq 'writethrough' || $cache eq 'directsync'; From 4cbe5a6ef1db600a4c0c72109d8e3647473c69a0 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 13 Aug 2025 10:58:37 +0200 Subject: [PATCH 17/79] drive device: scsi: avoid setting nonexistent 'device_id' for scsi-{block, generic} Fixes: 46d1225e ("drive device: fix regression with missing '/dev/disk/by-id' paths") Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250813085845.25516-3-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 99d4da4f..78cfad62 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1235,8 +1235,11 @@ sub print_drivedevice_full { } $device .= ",id=$drive_id"; - # for the switch to -blockdev, the SCSI device ID needs to be explicitly specified - if (min_version($machine_version, 10, 0)) { + # For the switch to -blockdev, the SCSI device ID needs to be explicitly specified. Note + # that only ide-cd and ide-hd have a 'device_id' option. + if ( + min_version($machine_version, 10, 0) && ($device_type eq 'cd' || $device_type eq 'hd') + ) { $device .= ",device_id=drive-${drive_id}"; } From 4ce7b7dfced8838a49f3dd797c96159ee3355854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 14 Aug 2025 10:42:52 +0200 Subject: [PATCH 18/79] dbus-vmstate: fix installation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit there's no need to have a separate Makefile and directory for these, it's just files being copied. the missing handling of $PACKAGE in the old Makefile resulted in the files being installed in the wrong place when building the source package.. Reported-by: Fiona Ebner Signed-off-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250814084409.182322-1-f.gruenbichler@proxmox.com --- src/Makefile | 1 - src/dbus-vmstate/Makefile | 11 ----------- src/usr/Makefile | 7 +++++++ src/{dbus-vmstate => usr}/dbus-vmstate | 0 src/{dbus-vmstate => usr}/org.qemu.VMState1.conf | 0 src/{dbus-vmstate => usr}/pve-dbus-vmstate@.service | 0 6 files changed, 7 insertions(+), 12 deletions(-) delete mode 100644 src/dbus-vmstate/Makefile rename src/{dbus-vmstate => usr}/dbus-vmstate (100%) rename src/{dbus-vmstate => usr}/org.qemu.VMState1.conf (100%) rename src/{dbus-vmstate => usr}/pve-dbus-vmstate@.service (100%) diff --git a/src/Makefile b/src/Makefile index 3f9b8c6f..f8e9a2d9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,7 +6,6 @@ install: $(MAKE) -C bin install $(MAKE) -C qmeventd install $(MAKE) -C query-machine-capabilities install - $(MAKE) -C dbus-vmstate install $(MAKE) -C usr install .PHONY: test diff --git a/src/dbus-vmstate/Makefile b/src/dbus-vmstate/Makefile deleted file mode 100644 index ced00264..00000000 --- a/src/dbus-vmstate/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -export LIBEXECDIR := $(DESTDIR)/usr/libexec/$(PACKAGE) -export LIBSYSTEMDDIR := $(DESTDIR)/usr/lib/systemd -export DBUSDIR := $(DESTDIR)/usr/share/dbus-1 - -all: - -.PHONY: install -install: - install -D -m 0755 dbus-vmstate $(LIBEXECDIR)/dbus-vmstate - install -D -m 0644 pve-dbus-vmstate@.service $(LIBSYSTEMDDIR)/system/pve-dbus-vmstate@.service - install -D -m 0644 org.qemu.VMState1.conf $(DBUSDIR)/system.d/org.qemu.VMState1.conf diff --git a/src/usr/Makefile b/src/usr/Makefile index 321e44c4..1365544b 100644 --- a/src/usr/Makefile +++ b/src/usr/Makefile @@ -3,6 +3,8 @@ DESTDIR= PREFIX=/usr LIBDIR=$(DESTDIR)/$(PREFIX)/lib LIBEXECDIR=$(DESTDIR)/$(PREFIX)/libexec/$(PACKAGE) +LIBSYSTEMDDIR := $(DESTDIR)/usr/lib/systemd +DBUSDIR := $(DESTDIR)/usr/share/dbus-1 SHAREDIR=$(DESTDIR)/$(PREFIX)/share/$(PACKAGE) .PHONY: install @@ -17,6 +19,11 @@ install: pve-usb.cfg pve-q35.cfg pve-q35-4.0.cfg bootsplash.jpg modules-load.con install -m 0755 pve-bridge $(LIBEXECDIR)/pve-bridge install -m 0755 pve-bridge-hotplug $(LIBEXECDIR)/pve-bridge-hotplug install -m 0755 pve-bridgedown $(LIBEXECDIR)/pve-bridgedown + install -D -m 0755 dbus-vmstate $(LIBEXECDIR)/dbus-vmstate + install -d $(LIBSYSTEMDDIR) + install -D -m 0644 pve-dbus-vmstate@.service $(LIBSYSTEMDDIR)/system/pve-dbus-vmstate@.service + install -d $(DBUSDIR) + install -D -m 0644 org.qemu.VMState1.conf $(DBUSDIR)/system.d/org.qemu.VMState1.conf .PHONY: clean clean: diff --git a/src/dbus-vmstate/dbus-vmstate b/src/usr/dbus-vmstate similarity index 100% rename from src/dbus-vmstate/dbus-vmstate rename to src/usr/dbus-vmstate diff --git a/src/dbus-vmstate/org.qemu.VMState1.conf b/src/usr/org.qemu.VMState1.conf similarity index 100% rename from src/dbus-vmstate/org.qemu.VMState1.conf rename to src/usr/org.qemu.VMState1.conf diff --git a/src/dbus-vmstate/pve-dbus-vmstate@.service b/src/usr/pve-dbus-vmstate@.service similarity index 100% rename from src/dbus-vmstate/pve-dbus-vmstate@.service rename to src/usr/pve-dbus-vmstate@.service From bf3fc3ce6d4480075dfd1e33d0b95f29c7a511ab Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 14 Aug 2025 12:41:44 +0200 Subject: [PATCH 19/79] bump version to 9.0.18 Signed-off-by: Fiona Ebner --- debian/changelog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4989804f..66bc1975 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +qemu-server (9.0.18) trixie; urgency=medium + + * close #6378: expose guest-phys-bits CPU option. + + * fix #6675: template backup: fix regression with IDE/SATA and blockdev. + + * fix #6680: avoid setting nonexistent 'write-cache' and 'drive_id' options + for passed-through disks using SCSI with machine version >= 10.0. + + * dbus-vmstate: fix installation path for script. + + -- Proxmox Support Team Thu, 14 Aug 2025 12:33:11 +0200 + qemu-server (9.0.17) trixie; urgency=medium * fix #6648: api: machine versions: fix ordering From 240be36667e2278b6c63433731aa3902d9fb51c1 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 14 Aug 2025 15:06:00 +0200 Subject: [PATCH 20/79] live import: correctly generate blockdev The throttle node is generated later above the alloc-track block node, so generating the alloc-track backing block node needs to happen with 'no-throttle' to avoid a duplicate node name and avoid an additional throttle node in the graph. Reported in the community forum: https://forum.proxmox.com/threads/169766/ Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 78cfad62..f263fedb 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -7379,7 +7379,7 @@ sub live_import_from_files { my ($interface, $index) = PVE::QemuServer::Drive::parse_drive_interface($dev); my $drive = { file => $volid, interface => $interface, index => $index }; my $blockdev = PVE::QemuServer::Blockdev::generate_drive_blockdev( - $storecfg, $drive, $machine_version, {}, + $storecfg, $drive, $machine_version, { 'no-throttle' => 1 }, ); $live_restore_backing->{$dev}->{blockdev} = $blockdev; } else { From eb95d270298929fbc2e23e9bb2dbceb8bad237e1 Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Mon, 18 Aug 2025 14:30:59 +0200 Subject: [PATCH 21/79] api: dbus-vmstate: reword description to match behaviour This method allows to perform either a 'start' or 'stop' action on the DBus VMState helper, not just stop it. Signed-off-by: Christoph Heiss Link: https://lore.proxmox.com/20250818123141.841088-2-c.heiss@proxmox.com --- src/PVE/API2/Qemu.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 83542482..b571e6c1 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -6956,7 +6956,7 @@ __PACKAGE__->register_method({ path => '{vmid}/dbus-vmstate', method => 'POST', proxyto => 'node', - description => 'Stop the dbus-vmstate helper for the given VM if running.', + description => 'Control the dbus-vmstate helper for a given running VM.', permissions => { check => ['perm', '/vms/{vmid}', ['VM.Migrate']], }, From c031d373d178c794cc7cb4fde2fd10dfca28a340 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 14 Aug 2025 18:45:07 +0200 Subject: [PATCH 22/79] fix #6680 (continued): do not use a top throttle node when using scsi-block The throttle block driver does not support issuing ioctls. While the driver could be patched in QEMU to pass along ioctls to the child, that seems like a hack, because with scsi-block, throttle limits already do not apply. This was already the case with '-drive' in Proxmox VE 8. Note that live mirroring would require special handling to make the target be below a throttle node with the correct node name, but it already is not supported for such disks: > # qm disk move 103 scsi1 lvm > unable to parse volume ID '/dev/sdg' Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250814164529.694979-1-f.ebner@proxmox.com --- src/PVE/QemuServer/Blockdev.pm | 8 ++++++++ src/test/cfg2cmd/scsiblk.conf | 5 +++++ src/test/cfg2cmd/scsiblk.conf.cmd | 32 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/cfg2cmd/scsiblk.conf create mode 100644 src/test/cfg2cmd/scsiblk.conf.cmd diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index f5798cbf..d4062148 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -478,6 +478,14 @@ sub generate_drive_blockdev { }; } + if ($drive->{scsiblock}) { + # When using scsi-block for the front-end device, throttling would not work in any case, and + # the throttle block driver doesn't allow doing the necessary ioctls(), so don't attach a + # throttle filter. Implementing live mirroring for such disks would require special care! + $child->{'node-name'} = top_node_name($drive_id); + return $child; + } + # for fleecing and TPM backup, this is already the top node return $child if $options->{fleecing} || $options->{'tpm-backup'} || $options->{'no-throttle'}; diff --git a/src/test/cfg2cmd/scsiblk.conf b/src/test/cfg2cmd/scsiblk.conf new file mode 100644 index 00000000..c767cef6 --- /dev/null +++ b/src/test/cfg2cmd/scsiblk.conf @@ -0,0 +1,5 @@ +boot: order=scsi0 +meta: creation-qemu=10.0.2,ctime=1755189639 +scsi0: /dev/sdg,scsiblock=1,size=32G +smbios1: uuid=d47e2d5c-7068-46d4-9733-ff94083e28f6 +vmgenid: 0a212e2f-0d9a-4006-971e-17be9fcf3efe diff --git a/src/test/cfg2cmd/scsiblk.conf.cmd b/src/test/cfg2cmd/scsiblk.conf.cmd new file mode 100644 index 00000000..3f99b405 --- /dev/null +++ b/src/test/cfg2cmd/scsiblk.conf.cmd @@ -0,0 +1,32 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smbios 'type=1,uuid=d47e2d5c-7068-46d4-9733-ff94083e28f6' \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'vmgenid,guid=0a212e2f-0d9a-4006-971e-17be9fcf3efe' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'lsi,id=scsihw0,bus=pci.0,addr=0x5' \ + -blockdev '{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"raw","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"host_device","filename":"/dev/sdg","node-name":"e8c91179e47ae3eb292a03618be5cf4","read-only":false},"node-name":"drive-scsi0","read-only":false}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -machine 'type=pc+pve0' From 22e4a77eaaf9d57f0c95f56d03ef9a9f0f44bf9e Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Tue, 26 Aug 2025 09:29:10 +0200 Subject: [PATCH 23/79] bump version to 9.0.19 Signed-off-by: Thomas Lamprecht --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 66bc1975..8ad7e5e1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +qemu-server (9.0.19) trixie; urgency=medium + + * fix generating block-dev option on VM live import. + + * fix #6680: do not use a top throttle node when using scsi-block, like for + passthrough of SCSI devices. + + -- Proxmox Support Team Tue, 26 Aug 2025 09:35:28 +0200 + qemu-server (9.0.18) trixie; urgency=medium * close #6378: expose guest-phys-bits CPU option. From 189aecb47855a1c3c450c19aef04303213171cb0 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Tue, 26 Aug 2025 11:19:46 +0200 Subject: [PATCH 24/79] d/changelog: expand some recent entries To have some more context for the users reading these, also drop those that are just referencing refactoring/preparation commits. Signed-off-by: Thomas Lamprecht --- debian/changelog | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index 8ad7e5e1..63acb751 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,13 +3,17 @@ qemu-server (9.0.19) trixie; urgency=medium * fix generating block-dev option on VM live import. * fix #6680: do not use a top throttle node when using scsi-block, like for - passthrough of SCSI devices. + passthrough of SCSI devices and 10+ machine version, as passed through + disks do not support bandwidth limitations. -- Proxmox Support Team Tue, 26 Aug 2025 09:35:28 +0200 qemu-server (9.0.18) trixie; urgency=medium - * close #6378: expose guest-phys-bits CPU option. + * close #6378: expose guest-phys-bits CPU option to cope with using the host + CPU type on CPU models where the CPU address width and the IOMMU address + width are different. On such systems the guest-phys-bits option needs to + be set to properly support huge pages and/or VFIO. * fix #6675: template backup: fix regression with IDE/SATA and blockdev. @@ -22,15 +26,18 @@ qemu-server (9.0.18) trixie; urgency=medium qemu-server (9.0.17) trixie; urgency=medium - * fix #6648: api: machine versions: fix ordering + * fix #6648: api: available machine versions: ensure array of versions is + correctly ordered numerically. - * prohibit using snapshot-as-volume-chain qcow2 images with pre-10.0 machines + * prohibit using snapshot-as-volume-chain qcow2 images with VMs that use a + pre-10.0 machine version. - * qmp client: add $noerr argument + * blockdev: attach/detach: silence errors for QMP commands for which failure + may be expected. - * blockdev: attach/detach: silence errors for QMP commands for which failure may be expected - - * blockdev: delete/replace: re-use detach() helper + * blockdev: delete/replace: re-use common detach helper to avoid + false-positive errors in the syslog for devices that QEMU already + auto-removes itself. -- Proxmox Support Team Tue, 12 Aug 2025 15:10:38 +0200 From 96c6e79b2558ff9c6fc32ca3f97d44cdb6e4a73d Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 1 Sep 2025 15:32:14 +0200 Subject: [PATCH 25/79] api: minor schema fixup: 'string' is a type, not a format Signed-off-by: Wolfgang Bumiller --- src/PVE/API2/Qemu/Agent.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu/Agent.pm b/src/PVE/API2/Qemu/Agent.pm index 05ef4f50..a083ed62 100644 --- a/src/PVE/API2/Qemu/Agent.pm +++ b/src/PVE/API2/Qemu/Agent.pm @@ -327,7 +327,7 @@ __PACKAGE__->register_method({ type => 'array', description => 'The command as a list of program + arguments.', items => { - format => 'string', + type => 'string', description => 'A single part of the program + arguments.', }, }, From b4c7f9b0f70267c84fc29e2e346eee24115ca4a5 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 3 Sep 2025 10:01:12 +0200 Subject: [PATCH 26/79] run make tidy Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index f263fedb..38fa3f83 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -7379,7 +7379,10 @@ sub live_import_from_files { my ($interface, $index) = PVE::QemuServer::Drive::parse_drive_interface($dev); my $drive = { file => $volid, interface => $interface, index => $index }; my $blockdev = PVE::QemuServer::Blockdev::generate_drive_blockdev( - $storecfg, $drive, $machine_version, { 'no-throttle' => 1 }, + $storecfg, + $drive, + $machine_version, + { 'no-throttle' => 1 }, ); $live_restore_backing->{$dev}->{blockdev} = $blockdev; } else { From 35a1828bdcbd9b54b379bc76a79b94f03df3cca3 Mon Sep 17 00:00:00 2001 From: Aaron Lauterer Date: Thu, 28 Aug 2025 14:58:09 +0200 Subject: [PATCH 27/79] api: rrd: add missing ds parameter for png graph MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, no png would be generated if that parameter is omitted Signed-off-by: Aaron Lauterer Tested-by: Michael Köppl Link: https://lore.proxmox.com/20250828125810.3642601-2-a.lauterer@proxmox.com --- src/PVE/API2/Qemu.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index b571e6c1..6069c3a9 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -1632,7 +1632,7 @@ __PACKAGE__->register_method({ my $path = "pve-vm-9.0/$param->{vmid}"; $path = "pve2-vm/$param->{vmid}" if !-e "/var/lib/rrdcached/db/${path}"; - return PVE::RRD::create_rrd_graph($path, $param->{timeframe}, $param->{cf}); + return PVE::RRD::create_rrd_graph($path, $param->{timeframe}, $param->{ds}, $param->{cf}); }, }); From ffa2fd05e13142c997aaf572216ee17c396e3a08 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:45 +0200 Subject: [PATCH 28/79] virtio-net: fix migration between default/non-default MTUs starting with machine version 10.0+pve1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtual hardware is generated differently (at least for i440fx machines) when host_mtu is set or not set on the netdev command line [0]. When the MTU is the same value as the default 1500, Proxmox VE did not add a host_mtu parameter. This is problematic for migration where host_mtu is present on one end of the migration, but not on the other [1]. Always set the host_mtu parameter starting with machine version 10.0+pve1 to avoid this issue going forward. Handling migrations with older machine versions is more involved and will be done in separate patches. Thanks to Stefan Hanreich and Fabian Grünbichler for discussing this with me! Since print_netdevice_full() is also called for hotplug, it cannot always use the $version_guard helper and needs to fallback to min_version() then. [0]: https://bugzilla.redhat.com/show_bug.cgi?id=1449346 [1]: https://forum.proxmox.com/threads/live-vm-migration-fails.169537/post-796379 Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-2-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 10 +++++++++- src/PVE/QemuServer/Machine.pm | 6 ++++++ src/test/cfg2cmd/bootorder-empty.conf.cmd | 4 ++-- src/test/cfg2cmd/bootorder-legacy.conf.cmd | 4 ++-- src/test/cfg2cmd/bootorder.conf.cmd | 4 ++-- src/test/cfg2cmd/efidisk-on-rbd.conf.cmd | 4 ++-- src/test/cfg2cmd/ide.conf.cmd | 4 ++-- src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd | 2 +- src/test/cfg2cmd/netdev-7.1.conf.cmd | 2 +- src/test/cfg2cmd/netdev_vxlan.conf.cmd | 2 +- src/test/cfg2cmd/q35-ide.conf.cmd | 4 ++-- src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd | 4 ++-- .../cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd | 4 ++-- .../cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd | 4 ++-- src/test/cfg2cmd/q35-linux-hostpci.conf.cmd | 4 ++-- src/test/cfg2cmd/q35-simple.conf.cmd | 4 ++-- src/test/cfg2cmd/seabios_serial.conf.cmd | 4 ++-- src/test/cfg2cmd/simple-btrfs.conf.cmd | 4 ++-- src/test/cfg2cmd/simple-disk-passthrough.conf.cmd | 4 ++-- src/test/cfg2cmd/simple-rbd.conf.cmd | 4 ++-- src/test/cfg2cmd/simple-virtio-blk.conf.cmd | 4 ++-- src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd | 4 ++-- src/test/cfg2cmd/simple1.conf.cmd | 4 ++-- 23 files changed, 54 insertions(+), 40 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 38fa3f83..5b7087dc 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1495,7 +1495,13 @@ sub print_netdevice_full { die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n"; } - $tmpstr .= ",host_mtu=$mtu" if $mtu != 1500; + if (min_version($machine_version, 10, 0, 1)) { + # Always add host_mtu for migration compatibility, because the presence of host_mtu + # means that the virtual hardware is generated differently (at least for i440fx) + $tmpstr .= ",host_mtu=$mtu"; + } else { + $tmpstr .= ",host_mtu=$mtu" if $mtu != 1500; + } } elsif (defined($mtu)) { warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n"; @@ -3819,6 +3825,8 @@ sub config_to_command { my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, $netname); push @$devices, '-netdev', $netdevfull; + # force +pve1 if machine version 10.0, for host_mtu differentiation + $version_guard->(10, 0, 1); my $netdevicefull = print_netdevice_full( $vmid, $conf, diff --git a/src/PVE/QemuServer/Machine.pm b/src/PVE/QemuServer/Machine.pm index 9d17344a..4c135a20 100644 --- a/src/PVE/QemuServer/Machine.pm +++ b/src/PVE/QemuServer/Machine.pm @@ -37,6 +37,12 @@ our $PVE_MACHINE_VERSION = { '+pve1' => 'Disables S3/S4 power states by default.', }, }, + '10.0' => { + highest => 1, + revisions => { + '+pve1' => 'Set host_mtu vNIC option even with default value for migration compat.', + }, + }, }; my $machine_fmt = { diff --git a/src/test/cfg2cmd/bootorder-empty.conf.cmd b/src/test/cfg2cmd/bootorder-empty.conf.cmd index 3516b344..af4a5ba6 100644 --- a/src/test/cfg2cmd/bootorder-empty.conf.cmd +++ b/src/test/cfg2cmd/bootorder-empty.conf.cmd @@ -39,5 +39,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"eeb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"feb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"drive-virtio1","read-only":false,"throttle-group":"throttle-drive-virtio1"}' \ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/bootorder-legacy.conf.cmd b/src/test/cfg2cmd/bootorder-legacy.conf.cmd index c86ab6f9..6b848a9b 100644 --- a/src/test/cfg2cmd/bootorder-legacy.conf.cmd +++ b/src/test/cfg2cmd/bootorder-legacy.conf.cmd @@ -39,5 +39,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"eeb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"feb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"drive-virtio1","read-only":false,"throttle-group":"throttle-drive-virtio1"}' \ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,bootindex=302,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=100' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=100,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/bootorder.conf.cmd b/src/test/cfg2cmd/bootorder.conf.cmd index 48f9da8b..a3c6bd39 100644 --- a/src/test/cfg2cmd/bootorder.conf.cmd +++ b/src/test/cfg2cmd/bootorder.conf.cmd @@ -39,5 +39,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"eeb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"feb683fb9c516c1a8707c917f0d7a38","read-only":false},"node-name":"drive-virtio1","read-only":false,"throttle-group":"throttle-drive-virtio1"}' \ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=101' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=101,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd b/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd index 5d0c8aff..dda9d91b 100644 --- a/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd +++ b/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd @@ -31,5 +31,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=pc+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=pc+pve1' diff --git a/src/test/cfg2cmd/ide.conf.cmd b/src/test/cfg2cmd/ide.conf.cmd index 6b5a52a9..23282a18 100644 --- a/src/test/cfg2cmd/ide.conf.cmd +++ b/src/test/cfg2cmd/ide.conf.cmd @@ -42,5 +42,5 @@ -blockdev '{"detect-zeroes":"on","discard":"ignore","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"file","filename":"/var/lib/vz/images/100/vm-100-disk-2.qcow2","node-name":"ec11e0572184321efc5835152b95d5d","read-only":false},"node-name":"fc11e0572184321efc5835152b95d5d","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd b/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd index 776bab30..43e40742 100644 --- a/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd +++ b/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on,queues=2' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,vectors=6,mq=on,packed=on,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=900' \ - -machine 'type=pc+pve0' + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/netdev-7.1.conf.cmd b/src/test/cfg2cmd/netdev-7.1.conf.cmd index 0d6b3ad2..10404de4 100644 --- a/src/test/cfg2cmd/netdev-7.1.conf.cmd +++ b/src/test/cfg2cmd/netdev-7.1.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=900' \ - -machine 'type=pc+pve0' + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/netdev_vxlan.conf.cmd b/src/test/cfg2cmd/netdev_vxlan.conf.cmd index a2f3579d..7de574a7 100644 --- a/src/test/cfg2cmd/netdev_vxlan.conf.cmd +++ b/src/test/cfg2cmd/netdev_vxlan.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1450' \ - -machine 'type=pc+pve0' + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/q35-ide.conf.cmd b/src/test/cfg2cmd/q35-ide.conf.cmd index 475e58d9..9af48002 100644 --- a/src/test/cfg2cmd/q35-ide.conf.cmd +++ b/src/test/cfg2cmd/q35-ide.conf.cmd @@ -41,5 +41,5 @@ -blockdev '{"detect-zeroes":"on","discard":"ignore","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"file","filename":"/var/lib/vz/images/100/vm-100-disk-2.qcow2","node-name":"ec11e0572184321efc5835152b95d5d","read-only":false},"node-name":"fc11e0572184321efc5835152b95d5d","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=q35+pve1' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd index b0c3e587..7413a651 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd @@ -35,5 +35,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd index b4aa46f5..f8435778 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd @@ -35,5 +35,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd index 6c4937c7..b314b8ad 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd @@ -34,5 +34,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' diff --git a/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd index 19e6ba3c..b6914255 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd @@ -40,5 +40,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' diff --git a/src/test/cfg2cmd/q35-simple.conf.cmd b/src/test/cfg2cmd/q35-simple.conf.cmd index e3f712c3..9cdb5bdb 100644 --- a/src/test/cfg2cmd/q35-simple.conf.cmd +++ b/src/test/cfg2cmd/q35-simple.conf.cmd @@ -28,5 +28,5 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve0' + -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' diff --git a/src/test/cfg2cmd/seabios_serial.conf.cmd b/src/test/cfg2cmd/seabios_serial.conf.cmd index 8fc0509b..ce2d7cf2 100644 --- a/src/test/cfg2cmd/seabios_serial.conf.cmd +++ b/src/test/cfg2cmd/seabios_serial.conf.cmd @@ -31,5 +31,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"ecd04be4259153b8293415fefa2a84c","read-only":false},"node-name":"fcd04be4259153b8293415fefa2a84c","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'smm=off,type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'smm=off,type=pc+pve1' diff --git a/src/test/cfg2cmd/simple-btrfs.conf.cmd b/src/test/cfg2cmd/simple-btrfs.conf.cmd index f80421ad..b73aae79 100644 --- a/src/test/cfg2cmd/simple-btrfs.conf.cmd +++ b/src/test/cfg2cmd/simple-btrfs.conf.cmd @@ -40,5 +40,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/butter/bread/images/8006/vm-8006-disk-0/disk.raw","node-name":"e7487c01d831e2b51a5446980170ec9","read-only":false},"node-name":"f7487c01d831e2b51a5446980170ec9","read-only":false},"node-name":"drive-scsi3","read-only":false,"throttle-group":"throttle-drive-scsi3"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=3,drive=drive-scsi3,id=scsi3,device_id=drive-scsi3,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd b/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd index 987a6c82..2b3a22e5 100644 --- a/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd +++ b/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd @@ -36,5 +36,5 @@ -blockdev '{"detect-zeroes":"on","discard":"ignore","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"raw","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"on","discard":"ignore","driver":"file","filename":"/mnt/file.raw","node-name":"e234a4e3b89ac3adac9bdbf0c3dd6b4","read-only":false},"node-name":"f234a4e3b89ac3adac9bdbf0c3dd6b4","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/simple-rbd.conf.cmd b/src/test/cfg2cmd/simple-rbd.conf.cmd index b848672c..29dfaacc 100644 --- a/src/test/cfg2cmd/simple-rbd.conf.cmd +++ b/src/test/cfg2cmd/simple-rbd.conf.cmd @@ -52,5 +52,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/rbd-pve/fc4181a6-56eb-4f68-b452-8ba1f381ca2a/cpool/vm-8006-disk-0","node-name":"eb0b017124a47505c97a5da052e0141","read-only":false},"node-name":"fb0b017124a47505c97a5da052e0141","read-only":false},"node-name":"drive-scsi7","read-only":false,"throttle-group":"throttle-drive-scsi7"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=7,drive=drive-scsi7,id=scsi7,device_id=drive-scsi7,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/simple-virtio-blk.conf.cmd b/src/test/cfg2cmd/simple-virtio-blk.conf.cmd index a9acb0cf..efec4a20 100644 --- a/src/test/cfg2cmd/simple-virtio-blk.conf.cmd +++ b/src/test/cfg2cmd/simple-virtio-blk.conf.cmd @@ -31,5 +31,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"edd19f6c1b3a6d5a6248c3376a91a16","read-only":false},"node-name":"fdd19f6c1b3a6d5a6248c3376a91a16","read-only":false},"node-name":"drive-virtio0","read-only":false,"throttle-group":"throttle-drive-virtio0"}' \ -device 'virtio-blk-pci,drive=drive-virtio0,id=virtio0,bus=pci.0,addr=0xa,iothread=iothread-virtio0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd b/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd index 4fa6a5a9..21bfd638 100644 --- a/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd +++ b/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd @@ -40,5 +40,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"iscsi","lun":0,"node-name":"e915a332310039f7a3feed6901eb5da","portal":"127.0.0.1","read-only":false,"target":"iqn.2019-10.org.test:foobar","transport":"tcp"},"node-name":"f915a332310039f7a3feed6901eb5da","read-only":false},"node-name":"drive-scsi3","read-only":false,"throttle-group":"throttle-drive-scsi3"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=3,drive=drive-scsi3,id=scsi3,device_id=drive-scsi3,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' diff --git a/src/test/cfg2cmd/simple1.conf.cmd b/src/test/cfg2cmd/simple1.conf.cmd index 49b848f2..eef2868b 100644 --- a/src/test/cfg2cmd/simple1.conf.cmd +++ b/src/test/cfg2cmd/simple1.conf.cmd @@ -31,5 +31,5 @@ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/vm-8006-disk-0.qcow2","node-name":"ecd04be4259153b8293415fefa2a84c","read-only":false},"node-name":"fcd04be4259153b8293415fefa2a84c","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ - -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300' \ - -machine 'type=pc+pve0' + -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ + -machine 'type=pc+pve1' From c4d2ee0610e5df986d1ae75f634a17b7385288af Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:46 +0200 Subject: [PATCH 29/79] api: vm start: introduce nets-host-mtu parameter for migration compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtual hardware is generated differently (at least for i440fx machines) when host_mtu is set or not set on the netdev command line [0]. When the MTU is the same value as the default 1500, Proxmox VE did not add a host_mtu parameter. This is problematic for migration where host_mtu is present on one end of the migration, but not on the other [1]. Moreover, the effective setting in the guest (state) will still be the host_mtu from the source side, even if a different value is used for host_mtu on the target instance's commandline. This will not lead to an error loading the migration stream in QEMU, but having a larger host_mtu than the bridge MTU is still problematic for certain network traffic like > iperf3 -c 10.10.10.11 -u -l 2k when host_mtu=9000 and bridge MTU=1500. Starting a VM cold with such a configuration is already prohibited, so also prevent it for migration. Add the necessary parameter for VM start to allow preserving the values going forward. [0]: https://bugzilla.redhat.com/show_bug.cgi?id=1449346 [1]: https://forum.proxmox.com/threads/live-vm-migration-fails.169537/post-796379 Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-3-f.ebner@proxmox.com --- src/PVE/API2/Qemu.pm | 12 ++++++++++++ src/PVE/QemuServer.pm | 45 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 6069c3a9..6b921940 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -3383,6 +3383,16 @@ __PACKAGE__->register_method({ default => 0, description => 'Whether to migrate conntrack entries for running VMs.', }, + 'nets-host-mtu' => { + type => 'string', + pattern => 'net\d+=\d+(,net\d+=\d+)*', + optional => 1, + description => + 'Used for migration compat. List of VirtIO network devices and their effective' + . ' host_mtu setting according to the QEMU object model on the source side of' + . ' the migration. A value of 0 means that the host_mtu parameter is to be' + . ' avoided for the corresponding device.', + }, }, }, returns => { @@ -3414,6 +3424,7 @@ __PACKAGE__->register_method({ my $targetstorage = $get_root_param->('targetstorage'); my $force_cpu = $get_root_param->('force-cpu'); my $with_conntrack_state = $get_root_param->('with-conntrack-state'); + my $nets_host_mtu = $get_root_param->('nets-host-mtu'); my $storagemap; @@ -3501,6 +3512,7 @@ __PACKAGE__->register_method({ forcemachine => $machine, timeout => $timeout, forcecpu => $force_cpu, + 'nets-host-mtu' => $nets_host_mtu, }; PVE::QemuServer::vm_start($storecfg, $vmid, $params, $migrate_opts); diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 5b7087dc..20e26cd5 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1457,7 +1457,17 @@ sub print_pbs_blockdev { } sub print_netdevice_full { - my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_version) = @_; + my ( + $vmid, + $conf, + $net, + $netid, + $bridges, + $use_old_bios_files, + $arch, + $machine_version, + $host_mtu_migration, # force this value for host_mtu, 0 means force absence of param + ) = @_; my $device = $net->{model}; if ($net->{model} eq 'virtio') { @@ -1484,18 +1494,29 @@ sub print_netdevice_full { my $mtu = $net->{mtu}; - if ($net->{model} eq 'virtio' && $net->{bridge}) { + my $migration_skip_host_mtu = defined($host_mtu_migration) && $host_mtu_migration == 0; + print "netdev $netid: not adding 'host_mtu' parameter for migration compat\n" + if $migration_skip_host_mtu; + + if ($net->{model} eq 'virtio' && $net->{bridge} && !$migration_skip_host_mtu) { my $bridge_mtu = PVE::Network::read_bridge_mtu($net->{bridge}); + if ($host_mtu_migration) { + print "netdev $netid: using 'host_mtu=$host_mtu_migration' for migration compat\n"; + $mtu = $host_mtu_migration; + } + if (!defined($mtu) || $mtu == 1) { $mtu = $bridge_mtu; } elsif ($mtu < 576) { die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n"; } elsif ($mtu > $bridge_mtu) { - die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n"; + die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'" + . " - adjust the MTU for the network device in the VM configuration, while ensuring" + . " that the bridge is configured as desired.\n"; } - if (min_version($machine_version, 10, 0, 1)) { + if (min_version($machine_version, 10, 0, 1) || $host_mtu_migration) { # Always add host_mtu for migration compatibility, because the presence of host_mtu # means that the virtual hardware is generated differently (at least for i440fx) $tmpstr .= ",host_mtu=$mtu"; @@ -1503,8 +1524,14 @@ sub print_netdevice_full { $tmpstr .= ",host_mtu=$mtu" if $mtu != 1500; } } elsif (defined($mtu)) { - warn - "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n"; + my $msg_prefix = "netdev $netid: ignoring MTU '$mtu'"; + if ($migration_skip_host_mtu) { + log_warn("$msg_prefix, not used on the source side according to migration parameters"); + } elsif (!$net->{bridge}) { + log_warn("$msg_prefix, no bridge configured"); + } else { + log_warn("$msg_prefix, not using VirtIO"); + } } if ($use_old_bios_files) { @@ -3810,6 +3837,8 @@ sub config_to_command { }, ); + my $nets_host_mtu = + { map { split('=', $_) } PVE::Tools::split_list($options->{'nets-host-mtu'}) }; for (my $i = 0; $i < $MAX_NETS; $i++) { my $netname = "net$i"; @@ -3836,6 +3865,7 @@ sub config_to_command { $use_old_bios_files, $arch, $machine_version, + $nets_host_mtu->{$netname}, ); push @$devices, '-device', $netdevicefull; @@ -5566,6 +5596,8 @@ sub vm_start { # }, # virtio2 => ... # } +# nets-host-mtu => Used for migration compat. List of VirtIO network devices and their effective +# host_mtu setting according to the QEMU object model on the source side of the migration. # migrate_opts: # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks) # migratedfrom => source node @@ -5678,6 +5710,7 @@ sub vm_start_nolock { 'force-machine' => $forcemachine, 'force-cpu' => $forcecpu, 'live-restore-backing' => $params->{'live-restore-backing'}, + 'nets-host-mtu' => $params->{'nets-host-mtu'}, }, ); From 20c91f7f3a212869eac9360fc515d59ad21924d1 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:47 +0200 Subject: [PATCH 30/79] migration: preserve host_mtu for virtio-net devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtual hardware is generated differently (at least for i440fx machines) when host_mtu is set or not set on the netdev command line [0]. When the MTU is the same value as the default 1500, Proxmox VE did not add a host_mtu parameter. This is problematic for migration where host_mtu is present on one end of the migration, but not on the other [1]. Moreover, the effective setting in the guest (state) will still be the host_mtu from the source side, even if a different value is used for host_mtu on the target instance's commandline. This will not lead to an error loading the migration stream in QEMU, but having a larger host_mtu than the bridge MTU is still problematic for certain network traffic like > iperf3 -c 10.10.10.11 -u -l 2k when host_mtu=9000 and bridge MTU=1500. Pass the values from the source to the target during migration to be able to preserve them. [0]: https://bugzilla.redhat.com/show_bug.cgi?id=1449346 [1]: https://forum.proxmox.com/threads/live-vm-migration-fails.169537/post-796379 Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-4-f.ebner@proxmox.com --- src/PVE/QemuMigrate.pm | 8 +++++++ src/PVE/QemuServer/Network.pm | 29 +++++++++++++++++++++++ src/test/MigrationTest/QemuMigrateMock.pm | 15 ++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index e18cc2aa..4381b542 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -998,6 +998,10 @@ sub phase2_start_local_cluster { push @$cmd, '--force-cpu', $start->{forcecpu}; } + if ($start->{'nets-host-mtu'}) { + push @$cmd, '--nets-host-mtu', $start->{'nets-host-mtu'}; + } + if ($self->{storage_migration}) { push @$cmd, '--targetstorage', ($self->{opts}->{targetstorage} // '1'); } @@ -1187,6 +1191,10 @@ sub phase2 { }, }; + if (my $nets_host_mtu = PVE::QemuServer::Network::get_nets_host_mtu($vmid, $conf)) { + $params->{start_params}->{'nets-host-mtu'} = $nets_host_mtu; + } + my ($tunnel_info, $spice_port); my @online_local_volumes = $self->filter_local_volumes('online'); diff --git a/src/PVE/QemuServer/Network.pm b/src/PVE/QemuServer/Network.pm index 56df83fb..eb8222e8 100644 --- a/src/PVE/QemuServer/Network.pm +++ b/src/PVE/QemuServer/Network.pm @@ -11,6 +11,8 @@ use PVE::Network::SDN::Zones; use PVE::RESTEnvironment qw(log_warn); use PVE::Tools qw($IPV6RE file_read_firstline); +use PVE::QemuServer::Monitor qw(mon_cmd); + my $nic_model_list = [ 'e1000', 'e1000-82540em', @@ -330,4 +332,31 @@ sub tap_plug { PVE::Network::SDN::Zones::tap_plug($iface, $bridge, $tag, $firewall, $trunks, $rate); } +sub get_nets_host_mtu { + my ($vmid, $conf) = @_; + + my $nets_host_mtu = []; + for my $opt (sort keys $conf->%*) { + next if $opt !~ m/^net(\d+)$/; + my $net = parse_net($conf->{$opt}); + next if $net->{model} ne 'virtio'; + + my $host_mtu = eval { + mon_cmd( + $vmid, 'qom-get', + path => "/machine/peripheral/$opt", + property => 'host_mtu', + ); + }; + if (my $err = $@) { + log_warn("$opt: could not query host_mtu - $err"); + } elsif (defined($host_mtu)) { + push $nets_host_mtu->@*, "${opt}=${host_mtu}"; + } else { + log_warn("$opt: got undefined value when querying host_mtu"); + } + } + return join(',', $nets_host_mtu->@*); +} + 1; diff --git a/src/test/MigrationTest/QemuMigrateMock.pm b/src/test/MigrationTest/QemuMigrateMock.pm index b04cf78b..421f0bb7 100644 --- a/src/test/MigrationTest/QemuMigrateMock.pm +++ b/src/test/MigrationTest/QemuMigrateMock.pm @@ -225,6 +225,21 @@ $qemu_server_machine_module->mock( my $qemu_server_network_module = Test::MockModule->new("PVE::QemuServer::Network"); $qemu_server_network_module->mock( del_nets_bridge_fdb => sub { return; }, + mon_cmd => sub { + my ($vmid, $command, %params) = @_; + + if ($command eq 'qom-get') { + if ( + $params{path} =~ m|^/machine/peripheral/net\d+$| + && $params{property} eq 'host_mtu' + ) { + return 1500; + } + die "mon_cmd (mocked) - implement me: $command for path '$params{path}' property" + . " '$params{property}'"; + } + die "mon_cmd (mocked) - implement me: $command"; + }, ); my $qemu_server_qmphelpers_module = Test::MockModule->new("PVE::QemuServer::QMPHelpers"); From 8595594d38f9b07bfe7ca9d2a049d2c019b41ab7 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:48 +0200 Subject: [PATCH 31/79] snapshot: save vmstate: avoid using deprecated check_running() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-5-f.ebner@proxmox.com --- src/PVE/QemuConfig.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index e0853d65..e3ba240e 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -244,7 +244,7 @@ sub __snapshot_save_vmstate { # get current QEMU -cpu argument to ensure consistency of custom CPU models my $runningcpu; - if (my $pid = PVE::QemuServer::check_running($vmid)) { + if (my $pid = PVE::QemuServer::Helpers::vm_running_locally($vmid)) { $runningcpu = PVE::QemuServer::CPUConfig::get_cpu_from_running_vm($pid); } From 0bcf41ed428ae7ab337c184ddf249843aac36f44 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:49 +0200 Subject: [PATCH 32/79] snapshot: save vmstate: die when PID cannot be obtained MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The call get_current_qemu_machine() already depends on the virtual machine running, so not being able to obtain the PID is very unexpected. Quietly not including the running CPU in the snapshot can lead to not being able to restore the snapshot later, so die early instead. Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-6-f.ebner@proxmox.com --- src/PVE/QemuConfig.pm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index e3ba240e..33cac3be 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -243,10 +243,9 @@ sub __snapshot_save_vmstate { my $runningmachine = PVE::QemuServer::Machine::get_current_qemu_machine($vmid); # get current QEMU -cpu argument to ensure consistency of custom CPU models - my $runningcpu; - if (my $pid = PVE::QemuServer::Helpers::vm_running_locally($vmid)) { - $runningcpu = PVE::QemuServer::CPUConfig::get_cpu_from_running_vm($pid); - } + my $pid = PVE::QemuServer::Helpers::vm_running_locally($vmid) + or die "cannot obtain PID for VM $vmid!\n"; + my $runningcpu = PVE::QemuServer::CPUConfig::get_cpu_from_running_vm($pid); if (!$suspend) { $conf = $conf->{snapshots}->{$snapname}; From 7ceb6b7255a696ede1b0ec1578a562bc7dd22d75 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 4 Sep 2025 14:40:50 +0200 Subject: [PATCH 33/79] snapshot: introduce running-nets-host-mtu property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For VirtIO network devices, it is necessary to preserve the values and presence of the host_mtu setting when restoring a snapshot. See commit "migration: preserve host_mtu for virtio-net devices" for details. Signed-off-by: Fiona Ebner Reviewed-by: Fabian Grünbichler Link: https://lore.proxmox.com/20250904124113.81772-7-f.ebner@proxmox.com --- src/PVE/API2/Qemu.pm | 1 + src/PVE/QemuConfig.pm | 6 ++++++ src/PVE/QemuServer.pm | 9 +++++++++ src/PVE/QemuServer/RunState.pm | 3 ++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 6b921940..2acacc22 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -2113,6 +2113,7 @@ my $update_vm_api = sub { } push @delete, 'runningmachine' if $conf->{runningmachine}; push @delete, 'runningcpu' if $conf->{runningcpu}; + push @delete, 'running-nets-host-mtu' if $conf->{'running-nets-host-mtu'}; } PVE::QemuConfig->check_lock($conf) if !$skiplock; diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index 33cac3be..d0844c4c 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -247,6 +247,8 @@ sub __snapshot_save_vmstate { or die "cannot obtain PID for VM $vmid!\n"; my $runningcpu = PVE::QemuServer::CPUConfig::get_cpu_from_running_vm($pid); + my $nets_host_mtu = PVE::QemuServer::Network::get_nets_host_mtu($vmid, $conf); + if (!$suspend) { $conf = $conf->{snapshots}->{$snapname}; } @@ -254,6 +256,7 @@ sub __snapshot_save_vmstate { $conf->{vmstate} = $statefile; $conf->{runningmachine} = $runningmachine; $conf->{runningcpu} = $runningcpu; + $conf->{'running-nets-host-mtu'} = $nets_host_mtu; return $statefile; } @@ -473,6 +476,8 @@ sub __snapshot_rollback_hook { # re-initializing its random number generator $conf->{vmgenid} = PVE::QemuServer::generate_uuid(); } + + $data->{'nets-host-mtu'} = delete($conf->{'running-nets-host-mtu'}); } return; @@ -513,6 +518,7 @@ sub __snapshot_rollback_vm_start { statefile => $vmstate, forcemachine => $data->{forcemachine}, forcecpu => $data->{forcecpu}, + 'nets-host-mtu' => $data->{'nets-host-mtu'}, }; PVE::QemuServer::vm_start($storecfg, $vmid, $params); } diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 20e26cd5..e312acb6 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -635,6 +635,15 @@ EODESCR pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re, format_description => 'QEMU -cpu parameter', }, + 'running-nets-host-mtu' => { + type => 'string', + pattern => 'net\d+=\d+(,net\d+=\d+)*', + optional => 1, + description => + 'List of VirtIO network devices and their effective host_mtu setting. A value of 0' + . ' means that the host_mtu parameter is to be avoided for the corresponding device.' + . ' This is used internally for snapshots.', + }, machine => get_standard_option('pve-qemu-machine'), arch => { description => "Virtual processor architecture. Defaults to the host.", diff --git a/src/PVE/QemuServer/RunState.pm b/src/PVE/QemuServer/RunState.pm index 05e7fb47..6a5fdbd7 100644 --- a/src/PVE/QemuServer/RunState.pm +++ b/src/PVE/QemuServer/RunState.pm @@ -104,7 +104,8 @@ sub vm_suspend { warn $@ if $@; PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); PVE::Storage::vdisk_free($storecfg, $vmstate); - delete $conf->@{qw(vmstate runningmachine runningcpu)}; + delete $conf->@{ + qw(vmstate runningmachine runningcpu running-nets-host-mtu)}; PVE::QemuConfig->write_config($vmid, $conf); }; warn $@ if $@; From 4ce85819589de6e36af25fded1610761cdea0c55 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Thu, 4 Sep 2025 19:49:31 +0200 Subject: [PATCH 34/79] bump version to 9.0.20 Signed-off-by: Thomas Lamprecht --- debian/changelog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debian/changelog b/debian/changelog index 63acb751..9033ada3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +qemu-server (9.0.20) trixie; urgency=medium + + * api: rrd: add missing ds parameter for generating PNG graph. + + * virtio-net: fix migration between default/non-default MTUs starting with + machine version 10.0+pve1. + + * api: vm start: introduce nets-host-mtu parameter for migration compat. + + * snapshot: introduce running-nets-host-mtu property. + + -- Proxmox Support Team Thu, 04 Sep 2025 19:49:27 +0200 + qemu-server (9.0.19) trixie; urgency=medium * fix generating block-dev option on VM live import. From dc52c006ce0527181556aaa363f49082cd613b5c Mon Sep 17 00:00:00 2001 From: Daniel Kral Date: Fri, 5 Sep 2025 16:15:06 +0200 Subject: [PATCH 35/79] fix #6608: expose viommu driver aw-bits option Since QEMU 9.2 [0], the default I/O address space bit width was raised from 39 bits to 48 bits for the Intel vIOMMU driver, which makes the aw-bits check introduced in [1] to trip for host CPUs with less than 48 bits physical address width from QEMU 9.2 onwards: vfio 0000:XX:YY.Z: Failed to set vIOMMU: aw-bits 48 > host aw-bits 39 For VFIO devices where a vIOMMU is in-use, QEMU fetches the IOVA ranges with the iommufd ioctl IOMMU_IOAS_IOVA_RANGES or the vfio_iommu_type1's VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE info, so 'phys-bits' doesn't change the behavior of the check. Therefore, expose the 'aw-bits' option of the intel-iommu and virtio-iommu QEMU drivers to allow users to set the value. [0] qemu ddd84fd0c1 ("intel_iommu: Set default aw_bits to 48 starting from QEMU 9.2") [1] qemu 77f6efc0ab ("intel_iommu: Check compatibility with host IOMMU capabilities") Signed-off-by: Daniel Kral Link: https://lore.proxmox.com/20250905141529.215689-1-d.kral@proxmox.com --- src/PVE/QemuServer.pm | 9 +++++-- src/PVE/QemuServer/Machine.pm | 24 +++++++++++++++--- .../cfg2cmd/q35-no-viommu-with-aw-bits.conf | 3 +++ .../cfg2cmd/q35-viommu-intel-aw-bits.conf | 2 ++ .../cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd | 25 +++++++++++++++++++ .../cfg2cmd/q35-viommu-virtio-aw-bits.conf | 2 ++ .../q35-viommu-virtio-aw-bits.conf.cmd | 25 +++++++++++++++++++ 7 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 src/test/cfg2cmd/q35-no-viommu-with-aw-bits.conf create mode 100644 src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf create mode 100644 src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd create mode 100644 src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf create mode 100644 src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf.cmd diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index e312acb6..c428e2d7 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3943,11 +3943,16 @@ sub config_to_command { PVE::QemuServer::Machine::assert_valid_machine_property($machine_conf); if (my $viommu = $machine_conf->{viommu}) { + my $viommu_devstr = ''; + $viommu_devstr .= ",aw-bits=$machine_conf->{'aw-bits'}" if $machine_conf->{'aw-bits'}; + if ($viommu eq 'intel') { - unshift @$devices, '-device', 'intel-iommu,intremap=on,caching-mode=on'; + $viommu_devstr = "intel-iommu,intremap=on,caching-mode=on$viommu_devstr"; + unshift @$devices, '-device', $viommu_devstr; push @$machineFlags, 'kernel-irqchip=split'; } elsif ($viommu eq 'virtio') { - push @$devices, '-device', 'virtio-iommu-pci'; + $viommu_devstr = "virtio-iommu-pci$viommu_devstr"; + push @$devices, '-device', $viommu_devstr; } } diff --git a/src/PVE/QemuServer/Machine.pm b/src/PVE/QemuServer/Machine.pm index 4c135a20..b2ff7e24 100644 --- a/src/PVE/QemuServer/Machine.pm +++ b/src/PVE/QemuServer/Machine.pm @@ -64,6 +64,16 @@ my $machine_fmt = { enum => ['intel', 'virtio'], optional => 1, }, + 'aw-bits' => { + type => 'number', + description => "Specifies the vIOMMU address space bit width.", + verbose_description => "Specifies the vIOMMU address space bit width.\n\n" + . "Intel vIOMMU supports a bit width of either 39 or 48 bits and" + . " VirtIO vIOMMU supports any bit width between 32 and 64 bits.", + minimum => 32, + maximum => 64, + optional => 1, + }, 'enable-s3' => { type => 'boolean', description => @@ -118,10 +128,18 @@ sub default_machine_for_arch { sub assert_valid_machine_property { my ($machine_conf) = @_; - my $q35 = $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0; - if ($machine_conf->{viommu} && $machine_conf->{viommu} eq "intel" && !$q35) { - die "to use Intel vIOMMU please set the machine type to q35\n"; + if ($machine_conf->{viommu} && $machine_conf->{viommu} eq "intel") { + my $q35 = $machine_conf->{type} && ($machine_conf->{type} =~ m/q35/) ? 1 : 0; + die "to use Intel vIOMMU please set the machine type to q35\n" if !$q35; + + die "Intel vIOMMU supports only 39 or 48 bits as address width\n" + if $machine_conf->{'aw-bits'} + && $machine_conf->{'aw-bits'} != 39 + && $machine_conf->{'aw-bits'} != 48; } + + die "cannot set aw-bits if no vIOMMU is configured\n" + if $machine_conf->{'aw-bits'} && !$machine_conf->{viommu}; } sub machine_type_is_q35 { diff --git a/src/test/cfg2cmd/q35-no-viommu-with-aw-bits.conf b/src/test/cfg2cmd/q35-no-viommu-with-aw-bits.conf new file mode 100644 index 00000000..06db33ab --- /dev/null +++ b/src/test/cfg2cmd/q35-no-viommu-with-aw-bits.conf @@ -0,0 +1,3 @@ +# TEST: Check that aw-bits cannot be set without viommu +# EXPECT_ERROR: cannot set aw-bits if no vIOMMU is configured +machine: q35,aw-bits=39 diff --git a/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf b/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf new file mode 100644 index 00000000..9e84e42e --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf @@ -0,0 +1,2 @@ +# TEST: Check if aw-bits are propagated correctly to intel-iommu device +machine: q35,viommu=intel,aw-bits=39 diff --git a/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd b/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd new file mode 100644 index 00000000..030ccaa5 --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-intel-aw-bits.conf.cmd @@ -0,0 +1,25 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -global 'ICH9-LPC.disable_s3=1' \ + -global 'ICH9-LPC.disable_s4=1' \ + -device 'intel-iommu,intremap=on,caching-mode=on,aw-bits=39' \ + -readconfig /usr/share/qemu-server/pve-q35-4.0.cfg \ + -device 'usb-tablet,id=tablet,bus=ehci.0,port=1' \ + -device 'VGA,id=vga,bus=pcie.0,addr=0x1' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=q35+pve0,kernel-irqchip=split' diff --git a/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf b/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf new file mode 100644 index 00000000..dd8ef1fd --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf @@ -0,0 +1,2 @@ +# TEST: Check if aw-bits are propagated correctly to virtio-iommu-pci device +machine: q35,viommu=virtio,aw-bits=39 diff --git a/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf.cmd b/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf.cmd new file mode 100644 index 00000000..c3b12eee --- /dev/null +++ b/src/test/cfg2cmd/q35-viommu-virtio-aw-bits.conf.cmd @@ -0,0 +1,25 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -global 'ICH9-LPC.disable_s3=1' \ + -global 'ICH9-LPC.disable_s4=1' \ + -readconfig /usr/share/qemu-server/pve-q35-4.0.cfg \ + -device 'usb-tablet,id=tablet,bus=ehci.0,port=1' \ + -device 'VGA,id=vga,bus=pcie.0,addr=0x1' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'virtio-iommu-pci,aw-bits=39' \ + -machine 'type=q35+pve0' From 05eb8e6394ca83e53cbf6a01e1a8848ff3d4d3e8 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 8 Sep 2025 10:37:24 +0200 Subject: [PATCH 36/79] cfg2cmd: inform users that setting guest-phys-bits might be necessary when setting aw-bits Until QEMU warns about this itself, inform the users here. Commit message below copied from [1]. If a virtual machine is setup with an intel-iommu device, QEMU allocates and maps the (virtual) I/O address space (IOAS) for a VFIO passthrough device with iommufd. In case of a mismatch of the address width of the host CPU and IOMMU CPU, the guest physical address space (GPAS) and memory-type range registers (MTRRs) are setup to the host CPU's address width, which causes IOAS to be allocated and mapped outside of the IOMMU's maximum guest address width (MGAW) and causes the following error from QEMU (the error message is copied from the user forum [0]): kvm: vfio_container_dma_map(0x5c9222494280, 0x380000000000, 0x10000, 0x78075ee70000) = -22 (Invalid argument) [0]: https://forum.proxmox.com/threads/169586/page-3#post-795717 [1]: https://lore.proxmox.com/pve-devel/20250902112307.124706-5-d.kral@proxmox.com/ Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index c428e2d7..bf229610 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3944,7 +3944,13 @@ sub config_to_command { if (my $viommu = $machine_conf->{viommu}) { my $viommu_devstr = ''; - $viommu_devstr .= ",aw-bits=$machine_conf->{'aw-bits'}" if $machine_conf->{'aw-bits'}; + if ($machine_conf->{'aw-bits'}) { + $viommu_devstr .= ",aw-bits=$machine_conf->{'aw-bits'}"; + + # TODO remove message once this gets properly checked/warned about in QEMU itself. + print "vIOMMU 'aw-bits' set to $machine_conf->{'aw-bits'}. Sometimes it is necessary to" + . " set the CPU's 'guest-phys-bits' to the same value.\n"; + } if ($viommu eq 'intel') { $viommu_devstr = "intel-iommu,intremap=on,caching-mode=on$viommu_devstr"; From 73897abcbddf9865e074fbcd5a3efeb7af3b55ff Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 8 Sep 2025 11:35:07 +0200 Subject: [PATCH 37/79] run make tidy Signed-off-by: Fiona Ebner --- src/PVE/API2/Qemu.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 2acacc22..c7929dbb 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -1632,7 +1632,8 @@ __PACKAGE__->register_method({ my $path = "pve-vm-9.0/$param->{vmid}"; $path = "pve2-vm/$param->{vmid}" if !-e "/var/lib/rrdcached/db/${path}"; - return PVE::RRD::create_rrd_graph($path, $param->{timeframe}, $param->{ds}, $param->{cf}); + return PVE::RRD::create_rrd_graph($path, $param->{timeframe}, $param->{ds}, + $param->{cf}); }, }); From 67d8d092b11c9c8dbb071f705977858416584989 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 11:16:57 +0200 Subject: [PATCH 38/79] migration: tell users to upgrade if nets-host-mtu is not supported In Proxmox VE 9, the default behavior for VirtIO network devices is to inherit the MTU from the bridge. This means that most migrations are potentially problematic when the nets-host-mtu parameter is not set, see commit 20c91f7f ("migration: preserve host_mtu for virtio-net devices"). While setting the parameter could be avoided in some cases, the information what MTU the target node bridges have is not readily available. Upgrading is already required to avoid actual problematic cases, so just tell people to upgrade when the target does not support preserving the VirtIO-net MTU yet in all cases. Suggested-by: Thomas Lamprecht Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250909091918.32254-2-f.ebner@proxmox.com --- src/PVE/QemuMigrate.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 4381b542..8fbabdfa 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -1053,6 +1053,7 @@ sub phase2_start_local_cluster { }; my $target_replicated_volumes = {}; + my $target_nets_host_mtu_not_supported; # Note: We try to keep $spice_ticket secret (do not pass via command line parameter) # instead we pipe it through STDIN @@ -1110,11 +1111,16 @@ sub phase2_start_local_cluster { }, errfunc => sub { my $line = shift; + $target_nets_host_mtu_not_supported = 1 + if $line =~ m/^Unknown option: nets-host-mtu/; $self->log('info', "[$self->{node}] $line"); }, noerr => 1, ); + die "node $self->{node} is too old for preserving VirtIO-net MTU, please upgrade\n" + if $target_nets_host_mtu_not_supported; + die "remote command failed with exit code $exitcode\n" if $exitcode; die "unable to detect remote migration address\n" From 096a1ac22877d766c0b74a7da20f9bc61cf837ca Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 11:16:58 +0200 Subject: [PATCH 39/79] migration: remove unused variable The $version variable has been unused since commit 898e9296 ("migrate: drop outdated PVE 7.2 check guarding cloudinit config section"). Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250909091918.32254-3-f.ebner@proxmox.com --- src/PVE/QemuMigrate.pm | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 8fbabdfa..0c60c38c 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -195,8 +195,6 @@ sub prepare { # test if VM exists my $conf = $self->{vmconf} = PVE::QemuConfig->load_config($vmid); - my $version = PVE::QemuServer::Helpers::get_node_pvecfg_version($self->{node}); - my $repl_conf = PVE::ReplicationConfig->new(); $self->{replication_jobcfg} = $repl_conf->find_local_replication_job($vmid, $self->{node}); $self->{is_replicated} = $repl_conf->check_for_existing_jobs($vmid, 1); From fbf6a480dadace57b998f15cd527fe201f2d9f45 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Wed, 10 Sep 2025 13:08:34 +0200 Subject: [PATCH 40/79] migration: make error for to-old target node even more explicitly In that the target node is meant, as while we printed the node name itself a user might miss that it refers to the target node when reading this error, especially with bigger clusters and rather similar node names like e.g. pve1, ..., pve11, pve12, ..., pve21. Signed-off-by: Thomas Lamprecht --- src/PVE/QemuMigrate.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 0c60c38c..7093c41e 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -1116,7 +1116,7 @@ sub phase2_start_local_cluster { noerr => 1, ); - die "node $self->{node} is too old for preserving VirtIO-net MTU, please upgrade\n" + die "target node $self->{node} is too old for preserving VirtIO-net MTU, please upgrade\n" if $target_nets_host_mtu_not_supported; die "remote command failed with exit code $exitcode\n" if $exitcode; From be406571a200965d4779a0c62b0c7245d5c716fc Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Wed, 10 Sep 2025 15:17:14 +0200 Subject: [PATCH 41/79] bump version to 9.0.21 Signed-off-by: Thomas Lamprecht --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 9033ada3..b93694c4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +qemu-server (9.0.21) trixie; urgency=medium + + * fix #6608: expose vIOMMU driver address space bit width 'aw-bits' option. + + * migration: tell users to upgrade the target node if nets-host-mtu is not + supported by the target qemu-server package version. + + -- Proxmox Support Team Wed, 10 Sep 2025 15:17:11 +0200 + qemu-server (9.0.20) trixie; urgency=medium * api: rrd: add missing ds parameter for generating PNG graph. From e19ee1bf717c5e0d7fbed9fab8254ff221bc89f0 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Mon, 15 Sep 2025 13:06:06 +0200 Subject: [PATCH 42/79] fix bad line continuations with mismatched quote characters We had some bad line continuations of longer string literals using a pattern like: 'foo" ."bar' I.e., a 'line1"."line2' instead of an actually working 'line1'.'line2' code. This still resulted in valid perl by luck, making it go unnoticed, but the resulting string was rather broken as it included the newline and .' code part for the line continuation. I noticed them due to bad indentation still using tabs, which was due to perltidy not touching string literals. Signed-off-by: Thomas Lamprecht --- src/PVE/API2/Qemu.pm | 8 ++++---- src/PVE/QemuServer.pm | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index c7929dbb..34f615d8 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -4637,8 +4637,8 @@ __PACKAGE__->register_method({ digest => { type => 'string', description => - 'Prevent changes if current configuration file has different SHA1" - ." digest. This can be used to prevent concurrent modifications.', + 'Prevent changes if current configuration file has different SHA1' + . ' digest. This can be used to prevent concurrent modifications.', maxLength => 40, optional => 1, }, @@ -4659,8 +4659,8 @@ __PACKAGE__->register_method({ 'target-digest' => { type => 'string', description => - 'Prevent changes if the current config file of the target VM has a" - ." different SHA1 digest. This can be used to detect concurrent modifications.', + 'Prevent changes if the current config file of the target VM has a' + . ' different SHA1 digest. This can be used to detect concurrent modifications.', maxLength => 40, optional => 1, }, diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index bf229610..cbcad749 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -747,8 +747,8 @@ my $cicustom_fmt = { meta => { type => 'string', optional => 1, - description => 'Specify a custom file containing all meta data passed to the VM via" - ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.', + description => 'Specify a custom file containing all meta data passed to the VM via' + . ' cloud-init. This is provider specific meaning configdrive2 and nocloud differ.', format => 'pve-volume-id', format_description => 'volume', }, From 6572ff578488da700123281ac447d2ad6bd1771f Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:25 +0200 Subject: [PATCH 43/79] partially fix #6805: api: clone: properly remove all snapshot-related info When cloning from a snapshot, the current VM state is not copied. Not all relevant properties were dropped, leading to some left-overs in the configuration of the clone target. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-2-f.ebner@proxmox.com --- src/PVE/API2/Qemu.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 34f615d8..8097ea87 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -4356,7 +4356,10 @@ __PACKAGE__->register_method({ || $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' - || $opt eq 'snapstate'; + || $opt eq 'snapstate' + || $opt eq 'runningcpu' + || $opt eq 'runningmachine' + || $opt eq 'running-nets-host-mtu'; # no need to copy unused images, because VMID(owner) changes anyways next if $opt =~ m/^unused\d+$/; From 7c05f0be9858543272c1254c83f4dfc266b97fe2 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:26 +0200 Subject: [PATCH 44/79] partially fix #6805: api: modify vm config: privilege checks for VM-state-related properties Currently, the VM-state-related properties 'runningcpu', 'runningmachine' and 'running-nets-host-mtu' are not supposed to end up in the VM configuration of a remote-migratable VM, because a suspended VM is not yet migratable. However, there was a bug and the properties were not removed after cloning from a snapshot, see commit "partially fix #6805: api: clone: properly remove all snapshot-related info". Upon remote migration, the property would be encountered and would be limited to root@pam only. Also, migrating suspended VMs might be implemented in the future, i.e. BZ issue #2252. To aid fixing bug #6805 and preparing for issue #2252 in the future, do proper privilege checking for configuration properties related to the running VM state. Note that the 'vmstate' property is already checked for in the check_vm_modify_config_perm() helper. Note that VM-state-related properties cannot be set via API by a user. Originally-by: Thomas Lamprecht Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-3-f.ebner@proxmox.com --- src/PVE/API2/Qemu.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 8097ea87..594c5d48 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -732,6 +732,7 @@ my $check_cpu_model_access = sub { my $cpuoptions = { 'cores' => 1, 'cpu' => 1, + 'runningcpu' => 1, 'cpulimit' => 1, 'cpuunits' => 1, 'numa' => 1, @@ -751,6 +752,7 @@ my $hwtypeoptions = { 'hotplug' => 1, 'kvm' => 1, 'machine' => 1, + 'runningmachine' => 1, 'scsihw' => 1, 'smbios1' => 1, 'tablet' => 1, @@ -957,7 +959,7 @@ my $check_vm_modify_config_perm = sub { $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.PowerMgmt']); } elsif ($diskoptions->{$opt}) { $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Disk']); - } elsif ($opt =~ m/^net\d+$/) { + } elsif ($opt =~ m/^net\d+$/ || $opt eq 'running-nets-host-mtu') { $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Network']); } elsif ($cloudinitoptions->{$opt} || $opt =~ m/^ipconfig\d+$/) { $rpcenv->check_vm_perm( From f1fe3b748967d204c85960703407e0e655bfbb39 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:27 +0200 Subject: [PATCH 45/79] api: create/update: disallow setting 'running-nets-host-mtu' via API Like the other snapshot-related properties, it should not be possible to set 'running-nets-host-mtu' via the API. Fixes: 7ceb6b72 ("snapshot: introduce running-nets-host-mtu property") Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-4-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index cbcad749..0ddddbf2 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1856,6 +1856,7 @@ sub json_config_properties { parent => 1, snaptime => 1, vmstate => 1, + 'running-nets-host-mtu' => 1, runningmachine => 1, runningcpu => 1, meta => 1, From 80236b100e8cf5660b3f5f459e78e0ba322e1f21 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:28 +0200 Subject: [PATCH 46/79] resume from suspended: properly handle 'nets-host-mtu' Fixes: 7ceb6b72 ("snapshot: introduce running-nets-host-mtu property") Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-5-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 0ddddbf2..e2d5358f 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5681,10 +5681,12 @@ sub vm_start_nolock { my $forcemachine = $params->{forcemachine}; my $forcecpu = $params->{forcecpu}; + my $nets_host_mtu = $params->{'nets-host-mtu'}; if ($resume) { # enforce machine and CPU type on suspended vm to ensure HW compatibility $forcemachine = $conf->{runningmachine}; $forcecpu = $conf->{runningcpu}; + $nets_host_mtu = $conf->{'running-nets-host-mtu'}; print "Resuming suspended VM\n"; } @@ -5731,7 +5733,7 @@ sub vm_start_nolock { 'force-machine' => $forcemachine, 'force-cpu' => $forcecpu, 'live-restore-backing' => $params->{'live-restore-backing'}, - 'nets-host-mtu' => $params->{'nets-host-mtu'}, + 'nets-host-mtu' => $nets_host_mtu, }, ); @@ -6035,7 +6037,7 @@ sub vm_start_nolock { PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); PVE::Storage::vdisk_free($storecfg, $vmstate); } - delete $conf->@{qw(lock vmstate runningmachine runningcpu)}; + delete $conf->@{qw(lock vmstate running-nets-host-mtu runningmachine runningcpu)}; PVE::QemuConfig->write_config($vmid, $conf); } From bd1a858f433e01dff8510173515004b3a91638e5 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:29 +0200 Subject: [PATCH 47/79] vm commandline: handle 'nets-host-mtu' property in snapshot Fixes: 7ceb6b72 ("snapshot: introduce running-nets-host-mtu property") Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-6-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index e2d5358f..90a8be3e 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -6068,6 +6068,7 @@ sub vm_commandline { # check for machine or CPU overrides in snapshot $options->{'force-machine'} = $snapshot->{runningmachine}; $options->{'force-cpu'} = $snapshot->{runningcpu}; + $options->{'nets-host-mtu'} = $snapshot->{'running-nets-host-mtu'}; $snapshot->{digest} = $conf->{digest}; # keep file digest for API From 0db14e60109ea91a558f0f08594583588ef9ec66 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 17 Sep 2025 18:30:30 +0200 Subject: [PATCH 48/79] vm start: remove left-over VM-state-related properties When cloning from a snapshot, VM-state-related properties would be accidentally copied, see commit "partially fix #6805: api: clone: properly remove all snapshot-related info". Detect and remove such left-over properties upon VM start. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250917163038.488710-7-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 90a8be3e..f7f85436 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5553,6 +5553,20 @@ sub vm_migrate_alloc_nbd_disks { return $nbd; } +my sub remove_left_over_vmstate_opts { + my ($vmid, $conf) = @_; + + my $found; + for my $opt (qw(running-nets-host-mtu runningmachine runningcpu)) { + if (defined($conf->{$opt})) { + print "No VM state set, removing left-over option '$opt'\n"; + delete $conf->{$opt}; + $found = 1; + } + } + PVE::QemuConfig->write_config($vmid, $conf) if $found; +} + # see vm_start_nolock for parameters, additionally: # migrate_opts: # storagemap = parsed storage map for allocating NBD disks @@ -6039,6 +6053,8 @@ sub vm_start_nolock { } delete $conf->@{qw(lock vmstate running-nets-host-mtu runningmachine runningcpu)}; PVE::QemuConfig->write_config($vmid, $conf); + } elsif (!$conf->{vmstate}) { + remove_left_over_vmstate_opts($vmid, $conf); } PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start'); From 5208318f8147305891a0b56c00cd1585eaa23f8c Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Wed, 17 Sep 2025 18:37:58 +0200 Subject: [PATCH 49/79] bump version to 9.0.22 Signed-off-by: Thomas Lamprecht --- debian/changelog | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/debian/changelog b/debian/changelog index b93694c4..2c1a8eed 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +qemu-server (9.0.22) trixie; urgency=medium + + * partially fix #6805: + - api: modify vm config: privilege checks for VM-state-related + properties. + - api: clone: properly remove all snapshot-related info. + + * api: create/update: disallow setting 'running-nets-host-mtu' via API. + + * resume from suspended: properly handle 'nets-host-mtu'. + + * vm command line: handle 'nets-host-mtu' property in snapshot. + + * vm start: remove left-over VM-state-related properties. + + * api schema: fix broken line continuation in the description for three + properties. + + -- Proxmox Support Team Wed, 17 Sep 2025 18:37:06 +0200 + qemu-server (9.0.21) trixie; urgency=medium * fix #6608: expose vIOMMU driver address space bit width 'aw-bits' option. From c5cfa92ebb99fd0398115e5ffd226dcb9bd16f67 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 19 Sep 2025 14:08:36 +0200 Subject: [PATCH 50/79] fix #6713: snapshot volume chain: fix snapshot after disk move with zeroinit After mirror, the node below throttle might not be the format node, but can also be a zeroinit node. In particular, this is the node that needs to be used by when replacing the blockdev for volume-chain snapshots for the 'current' snapshot. Look up the actually inserted node below throttle, rather than assuming that it's the format node. Also removes the $src_file_blockdev_name variable that has been unused since commit e7cf7c00 ("blockdev: delete/replace: re-use detach() helper"). Signed-off-by: Fiona Ebner Tested-By: Aaron Lauterer Link: https://lore.proxmox.com/20250919120848.60751-1-f.ebner@proxmox.com --- src/PVE/QemuServer/Blockdev.pm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index d4062148..8e6749e8 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -924,9 +924,15 @@ sub blockdev_replace { my $volid = $drive->{file}; my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); - my $src_name_options = $src_snap eq 'current' ? {} : { 'snapshot-name' => $src_snap }; - my $src_file_blockdev_name = get_node_name('file', $drive_id, $volid, $src_name_options); - my $src_fmt_blockdev_name = get_node_name('fmt', $drive_id, $volid, $src_name_options); + my $src_name_options = {}; + my $src_blockdev_name; + if ($src_snap eq 'current') { + # there might be other nodes on top like zeroinit, look up the current node below throttle + $src_blockdev_name = get_node_name_below_throttle($vmid, $deviceid, 1); + } else { + $src_name_options = { 'snapshot-name' => $src_snap }; + $src_blockdev_name = get_node_name('fmt', $drive_id, $volid, $src_name_options); + } my $target_file_blockdev = generate_file_blockdev( $storecfg, @@ -989,7 +995,7 @@ sub blockdev_replace { } # delete old file|fmt nodes - eval { detach($vmid, $src_fmt_blockdev_name); }; + eval { detach($vmid, $src_blockdev_name); }; warn "detaching block node for $src_snap failed - $@" if $@; } From d44663ce6dceb40c404d159eae7148947e0452c4 Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Wed, 24 Sep 2025 11:01:57 +0200 Subject: [PATCH 51/79] api: dbus-vmstate: fix return property name It's called `has-dbus-vmstate` in the actual returned object, not `dbus-vmstate`. Signed-off-by: Christoph Heiss Link: https://lore.proxmox.com/20250924090158.132032-1-c.heiss@proxmox.com --- src/PVE/API2/NodeCapabilities/Qemu/Migration.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/API2/NodeCapabilities/Qemu/Migration.pm b/src/PVE/API2/NodeCapabilities/Qemu/Migration.pm index 98d683c3..31879007 100644 --- a/src/PVE/API2/NodeCapabilities/Qemu/Migration.pm +++ b/src/PVE/API2/NodeCapabilities/Qemu/Migration.pm @@ -29,7 +29,7 @@ __PACKAGE__->register_method({ type => 'object', additionalProperties => 0, properties => { - 'dbus-vmstate' => { + 'has-dbus-vmstate' => { type => 'boolean', description => 'Whether the host supports live-migrating additional' . ' VM state via the dbus-vmstate helper.', From 528df523161aa424cc6dca69230eae1f9a503cef Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 25 Sep 2025 14:25:08 +0200 Subject: [PATCH 52/79] fix #6207: vm status: return undef values when disk{read, write} cannot be queried If disk read/write cannot be queried because of QMP timeout, they should not be reported as 0, because a consumer of the RRD stats cannot distinguish between 0 being an actual 0 value and 0 being an indicator for the absence of the real value. The RRD graphs in the UI will already show this correctly. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250925122829.70121-2-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index f7f85436..d6d0cb13 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -2731,8 +2731,8 @@ sub vmstatus { $d->{netout} = 0; $d->{netin} = 0; - $d->{diskread} = 0; - $d->{diskwrite} = 0; + $d->{diskread} = undef; + $d->{diskwrite} = undef; $d->{template} = 1 if PVE::QemuConfig->is_template($conf); From 31d6f5f63bd6edb6c43de3e0213d38199c350cd4 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 25 Sep 2025 14:25:09 +0200 Subject: [PATCH 53/79] vm status: also queue query-proxmox-support QMP commands The vmstatus() function is used by pvestatd and needs to be fast. However, the 'query-proxmox-support' querying is done sequentially for each VM and each query has its own timeout (it's the default 5 seconds). If QMP is blocked for some reason for a single VM, that already adds 5 seconds to the whole operation. Compared with the whole stats querying queue, which is allowed to use 3 seconds in total, this is rather extreme and needs to be fixed. Back when commit 6891fd70 ("print query-proxmox-support result in 'full' status") was implemented, not all supported QEMU versions in Proxmox VE implemented the 'query-proxmox-support' QMP command. Because of this, the queue might be interrupted if ordering this command too early. It still could've been ordered before the 'query-balloon' one, which also can fail. Nowadays, all supported QEMU versions do implement the command and this just returns static information which cannot fail (as long as QMP communication itself works), so it can also be ordered at the beginning of the queue (after the main 'query-status'). Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250925122829.70121-3-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index d6d0cb13..7d5ab718 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -2886,9 +2886,15 @@ sub vmstatus { $res->{$vmid}->{'running-qemu'} = $version; }; + my $proxmox_support_cb = sub { + my ($vmid, $resp) = @_; + $res->{$vmid}->{'proxmox-support'} = $resp->{'return'} // {}; + }; + my $statuscb = sub { my ($vmid, $resp) = @_; + $qmpclient->queue_cmd($vmid, $proxmox_support_cb, 'query-proxmox-support'); $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats'); $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines'); $qmpclient->queue_cmd($vmid, $versioncb, 'query-version'); @@ -2913,16 +2919,6 @@ sub vmstatus { $qmpclient->queue_execute(undef, 2); - foreach my $vmid (keys %$list) { - next if $opt_vmid && ($vmid ne $opt_vmid); - next if !$res->{$vmid}->{pid}; #not running - - # we can't use the $qmpclient since it might have already aborted on - # 'query-balloon', but this might also fail for older versions... - my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") }; - $res->{$vmid}->{'proxmox-support'} = $qemu_support // {}; - } - foreach my $vmid (keys %$list) { next if $opt_vmid && ($vmid ne $opt_vmid); $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus}; From d8dafa7f02bee10a9a45d123938a6b599d195d6c Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 1 Oct 2025 10:28:47 +0200 Subject: [PATCH 54/79] api: add missing snapshot info to get-config return schema These are included but missing in the schema. Add them so they are generated for the rust types. Signed-off-by: Wolfgang Bumiller --- src/PVE/API2/Qemu.pm | 16 ++++++++++------ src/PVE/QemuServer.pm | 23 +++++++++++++---------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 594c5d48..8bcd16b3 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -1721,13 +1721,17 @@ __PACKAGE__->register_method({ returns => { description => "The VM configuration.", type => "object", - properties => PVE::QemuServer::json_config_properties({ - digest => { - type => 'string', - description => - 'SHA1 digest of configuration file. This can be used to prevent concurrent modifications.', + properties => PVE::QemuServer::json_config_properties( + { + digest => { + type => 'string', + description => + 'SHA1 digest of configuration file. This can be used to prevent concurrent modifications.', + }, }, - }), + 0, + 1, + ), }, code => sub { my ($param) = @_; diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 7d5ab718..c9de9850 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -1850,17 +1850,20 @@ sub qemu_created_version_fixups { # add JSON properties for create and set function sub json_config_properties { - my ($prop, $with_disk_alloc) = @_; + my ($prop, $with_disk_alloc, $with_snapshot_info) = @_; - my $skip_json_config_opts = { - parent => 1, - snaptime => 1, - vmstate => 1, - 'running-nets-host-mtu' => 1, - runningmachine => 1, - runningcpu => 1, - meta => 1, - }; + my $skip_json_config_opts; + if (!$with_snapshot_info) { + $skip_json_config_opts = { + parent => 1, + snaptime => 1, + vmstate => 1, + 'running-nets-host-mtu' => 1, + runningmachine => 1, + runningcpu => 1, + meta => 1, + }; + } foreach my $opt (keys %$confdesc) { next if $skip_json_config_opts->{$opt}; From fc8065547cd19f61bb3bc6687a8722dcc5cdfc28 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 2 Oct 2025 14:01:09 +0200 Subject: [PATCH 55/79] tests: cfg2cmd: add tests for different SCSI controllers All existing test cases only used virtio-scsi-pci or default, add some coverage for others. Signed-off-by: Fiona Ebner --- src/test/cfg2cmd/scsihw-lsi.conf | 9 ++++ src/test/cfg2cmd/scsihw-lsi.conf.cmd | 45 ++++++++++++++++++ src/test/cfg2cmd/scsihw-lsi53c810.conf | 9 ++++ src/test/cfg2cmd/scsihw-lsi53c810.conf.cmd | 45 ++++++++++++++++++ src/test/cfg2cmd/scsihw-megasas.conf | 9 ++++ src/test/cfg2cmd/scsihw-megasas.conf.cmd | 42 +++++++++++++++++ src/test/cfg2cmd/scsihw-pvscsi.conf | 9 ++++ src/test/cfg2cmd/scsihw-pvscsi.conf.cmd | 42 +++++++++++++++++ .../cfg2cmd/scsihw-virtio-scsi-single.conf | 9 ++++ .../scsihw-virtio-scsi-single.conf.cmd | 47 +++++++++++++++++++ 10 files changed, 266 insertions(+) create mode 100644 src/test/cfg2cmd/scsihw-lsi.conf create mode 100644 src/test/cfg2cmd/scsihw-lsi.conf.cmd create mode 100644 src/test/cfg2cmd/scsihw-lsi53c810.conf create mode 100644 src/test/cfg2cmd/scsihw-lsi53c810.conf.cmd create mode 100644 src/test/cfg2cmd/scsihw-megasas.conf create mode 100644 src/test/cfg2cmd/scsihw-megasas.conf.cmd create mode 100644 src/test/cfg2cmd/scsihw-pvscsi.conf create mode 100644 src/test/cfg2cmd/scsihw-pvscsi.conf.cmd create mode 100644 src/test/cfg2cmd/scsihw-virtio-scsi-single.conf create mode 100644 src/test/cfg2cmd/scsihw-virtio-scsi-single.conf.cmd diff --git a/src/test/cfg2cmd/scsihw-lsi.conf b/src/test/cfg2cmd/scsihw-lsi.conf new file mode 100644 index 00000000..fd111842 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-lsi.conf @@ -0,0 +1,9 @@ +# TEST: Simple test for LSI SCSI controller +bootdisk: scsi0 +name: simple +scsi0: lvm-store:vm-8006-disk-0,discard=on,size=104858K +scsi1: lvm-store:vm-8006-disk-1,cache=writeback,discard=on,size=104858K +scsi5: lvm-store:vm-8006-disk-2,cache=writethrough,discard=on,size=104858K +scsi9: lvm-store:vm-8006-disk-3,cache=directsync,discard=on,size=104858K +scsi16: lvm-store:vm-8006-disk-4,cache=directsync,discard=on,size=104858K +scsihw: lsi diff --git a/src/test/cfg2cmd/scsihw-lsi.conf.cmd b/src/test/cfg2cmd/scsihw-lsi.conf.cmd new file mode 100644 index 00000000..0200215d --- /dev/null +++ b/src/test/cfg2cmd/scsihw-lsi.conf.cmd @@ -0,0 +1,45 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi1","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi5","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi9","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi16","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'pci-bridge,id=pci.4,chassis_nr=4,bus=pci.1,addr=0x1c' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'lsi,id=scsihw0,bus=pci.0,addr=0x5' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-0","node-name":"e0378a375d635b0f473569544c7c207","read-only":false},"node-name":"f0378a375d635b0f473569544c7c207","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-1","node-name":"e68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"f68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-2","node-name":"e02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"f02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"drive-scsi5","read-only":false,"throttle-group":"throttle-drive-scsi5"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=5,drive=drive-scsi5,id=scsi5,device_id=drive-scsi5,write-cache=off' \ + -device 'lsi,id=scsihw1,bus=pci.0,addr=0x6' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-3","node-name":"e77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"f77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"drive-scsi9","read-only":false,"throttle-group":"throttle-drive-scsi9"}' \ + -device 'scsi-hd,bus=scsihw1.0,scsi-id=2,drive=drive-scsi9,id=scsi9,device_id=drive-scsi9,write-cache=off' \ + -device 'lsi,id=scsihw2,bus=pci.4,addr=0x1' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-4","node-name":"e86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"f86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"drive-scsi16","read-only":false,"throttle-group":"throttle-drive-scsi16"}' \ + -device 'scsi-hd,bus=scsihw2.0,scsi-id=2,drive=drive-scsi16,id=scsi16,device_id=drive-scsi16,write-cache=off' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/scsihw-lsi53c810.conf b/src/test/cfg2cmd/scsihw-lsi53c810.conf new file mode 100644 index 00000000..58217419 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-lsi53c810.conf @@ -0,0 +1,9 @@ +# TEST: Simple test for LSI 53c810 SCSI controller +bootdisk: scsi0 +name: simple +scsi0: lvm-store:vm-8006-disk-0,discard=on,size=104858K +scsi1: lvm-store:vm-8006-disk-1,cache=writeback,discard=on,size=104858K +scsi5: lvm-store:vm-8006-disk-2,cache=writethrough,discard=on,size=104858K +scsi9: lvm-store:vm-8006-disk-3,cache=directsync,discard=on,size=104858K +scsi16: lvm-store:vm-8006-disk-4,cache=directsync,discard=on,size=104858K +scsihw: lsi53c810 diff --git a/src/test/cfg2cmd/scsihw-lsi53c810.conf.cmd b/src/test/cfg2cmd/scsihw-lsi53c810.conf.cmd new file mode 100644 index 00000000..fc27eaf0 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-lsi53c810.conf.cmd @@ -0,0 +1,45 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi1","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi5","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi9","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi16","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'pci-bridge,id=pci.4,chassis_nr=4,bus=pci.1,addr=0x1c' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'lsi53c810,id=scsihw0,bus=pci.0,addr=0x5' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-0","node-name":"e0378a375d635b0f473569544c7c207","read-only":false},"node-name":"f0378a375d635b0f473569544c7c207","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-1","node-name":"e68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"f68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-2","node-name":"e02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"f02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"drive-scsi5","read-only":false,"throttle-group":"throttle-drive-scsi5"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=5,drive=drive-scsi5,id=scsi5,device_id=drive-scsi5,write-cache=off' \ + -device 'lsi53c810,id=scsihw1,bus=pci.0,addr=0x6' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-3","node-name":"e77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"f77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"drive-scsi9","read-only":false,"throttle-group":"throttle-drive-scsi9"}' \ + -device 'scsi-hd,bus=scsihw1.0,scsi-id=2,drive=drive-scsi9,id=scsi9,device_id=drive-scsi9,write-cache=off' \ + -device 'lsi53c810,id=scsihw2,bus=pci.4,addr=0x1' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-4","node-name":"e86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"f86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"drive-scsi16","read-only":false,"throttle-group":"throttle-drive-scsi16"}' \ + -device 'scsi-hd,bus=scsihw2.0,scsi-id=2,drive=drive-scsi16,id=scsi16,device_id=drive-scsi16,write-cache=off' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/scsihw-megasas.conf b/src/test/cfg2cmd/scsihw-megasas.conf new file mode 100644 index 00000000..eef7b827 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-megasas.conf @@ -0,0 +1,9 @@ +# TEST: Simple test for MegaRAID SAS SCSI controller +bootdisk: scsi0 +name: simple +scsi0: lvm-store:vm-8006-disk-0,discard=on,size=104858K +scsi1: lvm-store:vm-8006-disk-1,cache=writeback,discard=on,size=104858K +scsi5: lvm-store:vm-8006-disk-2,cache=writethrough,discard=on,size=104858K +scsi9: lvm-store:vm-8006-disk-3,cache=directsync,discard=on,size=104858K +scsi16: lvm-store:vm-8006-disk-4,cache=directsync,discard=on,size=104858K +scsihw: megasas diff --git a/src/test/cfg2cmd/scsihw-megasas.conf.cmd b/src/test/cfg2cmd/scsihw-megasas.conf.cmd new file mode 100644 index 00000000..ab15c112 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-megasas.conf.cmd @@ -0,0 +1,42 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi1","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi5","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi9","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi16","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'megasas,id=scsihw0,bus=pci.0,addr=0x5' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-0","node-name":"e0378a375d635b0f473569544c7c207","read-only":false},"node-name":"f0378a375d635b0f473569544c7c207","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ + -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-1","node-name":"e68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"f68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ + -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-2","node-name":"e02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"f02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"drive-scsi5","read-only":false,"throttle-group":"throttle-drive-scsi5"}' \ + -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=5,drive=drive-scsi5,id=scsi5,device_id=drive-scsi5,write-cache=off' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-3","node-name":"e77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"f77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"drive-scsi9","read-only":false,"throttle-group":"throttle-drive-scsi9"}' \ + -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=9,drive=drive-scsi9,id=scsi9,device_id=drive-scsi9,write-cache=off' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-4","node-name":"e86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"f86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"drive-scsi16","read-only":false,"throttle-group":"throttle-drive-scsi16"}' \ + -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=16,drive=drive-scsi16,id=scsi16,device_id=drive-scsi16,write-cache=off' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/scsihw-pvscsi.conf b/src/test/cfg2cmd/scsihw-pvscsi.conf new file mode 100644 index 00000000..16b13469 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-pvscsi.conf @@ -0,0 +1,9 @@ +# TEST: Simple test for PVSCSI controller +bootdisk: scsi0 +name: simple +scsi0: lvm-store:vm-8006-disk-0,discard=on,size=104858K +scsi1: lvm-store:vm-8006-disk-1,cache=writeback,discard=on,size=104858K +scsi5: lvm-store:vm-8006-disk-2,cache=writethrough,discard=on,size=104858K +scsi9: lvm-store:vm-8006-disk-3,cache=directsync,discard=on,size=104858K +scsi16: lvm-store:vm-8006-disk-4,cache=directsync,discard=on,size=104858K +scsihw: pvscsi diff --git a/src/test/cfg2cmd/scsihw-pvscsi.conf.cmd b/src/test/cfg2cmd/scsihw-pvscsi.conf.cmd new file mode 100644 index 00000000..196683d3 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-pvscsi.conf.cmd @@ -0,0 +1,42 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi1","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi5","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi9","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi16","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'pvscsi,id=scsihw0,bus=pci.0,addr=0x5' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-0","node-name":"e0378a375d635b0f473569544c7c207","read-only":false},"node-name":"f0378a375d635b0f473569544c7c207","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-1","node-name":"e68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"f68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-2","node-name":"e02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"f02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"drive-scsi5","read-only":false,"throttle-group":"throttle-drive-scsi5"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=5,drive=drive-scsi5,id=scsi5,device_id=drive-scsi5,write-cache=off' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-3","node-name":"e77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"f77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"drive-scsi9","read-only":false,"throttle-group":"throttle-drive-scsi9"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=9,drive=drive-scsi9,id=scsi9,device_id=drive-scsi9,write-cache=off' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-4","node-name":"e86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"f86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"drive-scsi16","read-only":false,"throttle-group":"throttle-drive-scsi16"}' \ + -device 'scsi-hd,bus=scsihw0.0,scsi-id=16,drive=drive-scsi16,id=scsi16,device_id=drive-scsi16,write-cache=off' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf b/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf new file mode 100644 index 00000000..0f3d15be --- /dev/null +++ b/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf @@ -0,0 +1,9 @@ +# TEST: Simple test for VirtIO SCSI single controller +bootdisk: scsi0 +name: simple +scsi0: lvm-store:vm-8006-disk-0,discard=on,size=104858K +scsi1: lvm-store:vm-8006-disk-1,cache=writeback,discard=on,size=104858K +scsi5: lvm-store:vm-8006-disk-2,cache=writethrough,discard=on,size=104858K +scsi9: lvm-store:vm-8006-disk-3,cache=directsync,discard=on,size=104858K +scsi16: lvm-store:vm-8006-disk-4,cache=directsync,discard=on,size=104858K +scsihw: virtio-scsi-single diff --git a/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf.cmd b/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf.cmd new file mode 100644 index 00000000..2541eb49 --- /dev/null +++ b/src/test/cfg2cmd/scsihw-virtio-scsi-single.conf.cmd @@ -0,0 +1,47 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -object '{"id":"throttle-drive-scsi0","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi1","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi5","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi9","limits":{},"qom-type":"throttle-group"}' \ + -object '{"id":"throttle-drive-scsi16","limits":{},"qom-type":"throttle-group"}' \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'pci-bridge,id=pci.3,chassis_nr=3,bus=pci.0,addr=0x5' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -device 'virtio-scsi-pci,id=virtioscsi0,bus=pci.3,addr=0x1' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-0","node-name":"e0378a375d635b0f473569544c7c207","read-only":false},"node-name":"f0378a375d635b0f473569544c7c207","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ + -device 'scsi-hd,bus=virtioscsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ + -device 'virtio-scsi-pci,id=virtioscsi1,bus=pci.3,addr=0x2' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-1","node-name":"e68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"f68a63e6c55e4a6fe8c847a8f60af7e","read-only":false},"node-name":"drive-scsi1","read-only":false,"throttle-group":"throttle-drive-scsi1"}' \ + -device 'scsi-hd,bus=virtioscsi1.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ + -device 'virtio-scsi-pci,id=virtioscsi5,bus=pci.3,addr=0x6' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"threads","cache":{"direct":false,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-2","node-name":"e02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"f02ef0cb3873a2ecfddb04f546b6b26","read-only":false},"node-name":"drive-scsi5","read-only":false,"throttle-group":"throttle-drive-scsi5"}' \ + -device 'scsi-hd,bus=virtioscsi5.0,channel=0,scsi-id=0,lun=5,drive=drive-scsi5,id=scsi5,device_id=drive-scsi5,write-cache=off' \ + -device 'virtio-scsi-pci,id=virtioscsi9,bus=pci.3,addr=0xa' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-3","node-name":"e77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"f77e7a9ba0adc041419f45894ffb1ed","read-only":false},"node-name":"drive-scsi9","read-only":false,"throttle-group":"throttle-drive-scsi9"}' \ + -device 'scsi-hd,bus=virtioscsi9.0,channel=0,scsi-id=0,lun=9,drive=drive-scsi9,id=scsi9,device_id=drive-scsi9,write-cache=off' \ + -device 'virtio-scsi-pci,id=virtioscsi16,bus=pci.3,addr=0x11' \ + -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"host_device","filename":"/dev/veegee/vm-8006-disk-4","node-name":"e86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"f86ac0b43c3f3cb5be16052b349a9b7","read-only":false},"node-name":"drive-scsi16","read-only":false,"throttle-group":"throttle-drive-scsi16"}' \ + -device 'scsi-hd,bus=virtioscsi16.0,channel=0,scsi-id=0,lun=16,drive=drive-scsi16,id=scsi16,device_id=drive-scsi16,write-cache=off' \ + -machine 'type=pc+pve0' From 87ad8fd1b6b4741d33863be2609fb3eb847dc703 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier via pve-devel Date: Fri, 22 Aug 2025 16:17:53 +0200 Subject: [PATCH 56/79] introduce DriveDevice module and move print_drivedevice_full Signed-off-by: Alexandre Derumier Link: https://lore.proxmox.com/mailman.312.1755872353.385.pve-devel@lists.proxmox.com [FE: run make tidy] Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 167 +------------------------- src/PVE/QemuServer/DriveDevice.pm | 187 ++++++++++++++++++++++++++++++ src/PVE/QemuServer/Makefile | 1 + 3 files changed, 189 insertions(+), 166 deletions(-) create mode 100644 src/PVE/QemuServer/DriveDevice.pm diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index c9de9850..00b92b51 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -71,6 +71,7 @@ use PVE::QemuServer::Drive qw( print_drive storage_allows_io_uring_default ); +use PVE::QemuServer::DriveDevice qw(print_drivedevice_full scsihw_infos); use PVE::QemuServer::Machine; use PVE::QemuServer::Memory qw(get_current_memory); use PVE::QemuServer::MetaInfo; @@ -1205,150 +1206,6 @@ sub print_keyboarddevice_full { return "usb-kbd,id=keyboard,bus=ehci.0,port=2"; } -sub print_drivedevice_full { - my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_; - - my $device = ''; - my $maxdev = 0; - - my $machine_version = extract_version($machine_type, kvm_user_version()); - my $has_write_cache = 1; # whether the device has a 'write-cache' option - - my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); - if ($drive->{interface} eq 'virtio') { - my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch); - $device = 'virtio-blk-pci'; - # for the switch to -blockdev, there is no blockdev for 'none' - if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { - $device .= ",drive=drive-$drive_id"; - } - $device .= ",id=${drive_id}${pciaddr}"; - $device .= ",iothread=iothread-$drive_id" if $drive->{iothread}; - } elsif ($drive->{interface} eq 'scsi') { - - my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive); - my $unit = $drive->{index} % $maxdev; - - my $device_type = - PVE::QemuServer::Drive::get_scsi_device_type($drive, $storecfg, $machine_version); - - if (!$conf->{scsihw} || $conf->{scsihw} =~ m/^lsi/ || $conf->{scsihw} eq 'pvscsi') { - $device = "scsi-$device_type,bus=$controller_prefix$controller.0,scsi-id=$unit"; - } else { - $device = "scsi-$device_type,bus=$controller_prefix$controller.0,channel=0,scsi-id=0" - . ",lun=$drive->{index}"; - } - # for the switch to -blockdev, there is no blockdev for 'none' - if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { - $device .= ",drive=drive-$drive_id"; - } - $device .= ",id=$drive_id"; - - # For the switch to -blockdev, the SCSI device ID needs to be explicitly specified. Note - # that only ide-cd and ide-hd have a 'device_id' option. - if ( - min_version($machine_version, 10, 0) && ($device_type eq 'cd' || $device_type eq 'hd') - ) { - $device .= ",device_id=drive-${drive_id}"; - } - - if ($drive->{ssd} && ($device_type eq 'block' || $device_type eq 'hd')) { - $device .= ",rotation_rate=1"; - } - $device .= ",wwn=$drive->{wwn}" if $drive->{wwn}; - - # only scsi-hd and scsi-cd support passing vendor and product information and have a - # 'write-cache' option - if ($device_type eq 'hd' || $device_type eq 'cd') { - if (my $vendor = $drive->{vendor}) { - $device .= ",vendor=$vendor"; - } - if (my $product = $drive->{product}) { - $device .= ",product=$product"; - } - - $has_write_cache = 1; - } else { - $has_write_cache = 0; - } - - } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') { - my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2; - my $controller = int($drive->{index} / $maxdev); - my $unit = $drive->{index} % $maxdev; - - # machine type q35 only supports unit=0 for IDE rather than 2 units. This wasn't handled - # correctly before, so e.g. index=2 was mapped to controller=1,unit=0 rather than - # controller=2,unit=0. Note that odd indices never worked, as they would be mapped to - # unit=1, so to keep backwards compat for migration, it suffices to keep even ones as they - # were before. Move odd ones up by 2 where they don't clash. - if (PVE::QemuServer::Machine::machine_type_is_q35($conf) && $drive->{interface} eq 'ide') { - $controller += 2 * ($unit % 2); - $unit = 0; - } - - my $device_type = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd"; - - # With ide-hd, the inserted block node needs to be marked as writable too, but -blockdev - # will complain if it's marked as writable but the actual backing device is read-only (e.g. - # read-only base LV). IDE/SATA do not support being configured as read-only, the most - # similar is using ide-cd instead of ide-hd, with most of the code and configuration shared - # in QEMU. Since a template is never actually started, the front-end device is never - # accessed. The backup only accesses the inserted block node, so it does not matter for the - # backup if the type is 'ide-cd' instead. - $device_type = 'cd' if $conf->{template}; - - $device = "ide-$device_type"; - if ($drive->{interface} eq 'ide') { - $device .= ",bus=ide.$controller,unit=$unit"; - } else { - $device .= ",bus=ahci$controller.$unit"; - } - if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { - $device .= ",drive=drive-$drive_id"; - } - $device .= ",id=$drive_id"; - - if ($device_type eq 'hd') { - if (my $model = $drive->{model}) { - $model = URI::Escape::uri_unescape($model); - $device .= ",model=$model"; - } - if ($drive->{ssd}) { - $device .= ",rotation_rate=1"; - } - } - $device .= ",wwn=$drive->{wwn}" if $drive->{wwn}; - } elsif ($drive->{interface} eq 'usb') { - die "implement me"; - # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 - } else { - die "unsupported interface type"; - } - - $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex}; - - if (my $serial = $drive->{serial}) { - $serial = URI::Escape::uri_unescape($serial); - $device .= ",serial=$serial"; - } - - if (min_version($machine_version, 10, 0)) { # for the switch to -blockdev - if (!drive_is_cdrom($drive) && $has_write_cache) { - my $write_cache = 'on'; - if (my $cache = $drive->{cache}) { - $write_cache = 'off' if $cache eq 'writethrough' || $cache eq 'directsync'; - } - $device .= ",write-cache=$write_cache"; - } - for my $o (qw(rerror werror)) { - $device .= ",$o=$drive->{$o}" if defined($drive->{$o}); - } - } - - return $device; -} - sub print_drive_commandline_full { my ($storecfg, $vmid, $drive, $live_restore_name) = @_; @@ -8163,28 +8020,6 @@ sub vm_iothreads_list { return $iothreads; } -sub scsihw_infos { - my ($conf, $drive) = @_; - - my $maxdev = 0; - - if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) { - $maxdev = 7; - } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) { - $maxdev = 1; - } else { - $maxdev = 256; - } - - my $controller = int($drive->{index} / $maxdev); - my $controller_prefix = - ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') - ? "virtioscsi" - : "scsihw"; - - return ($maxdev, $controller, $controller_prefix); -} - sub resolve_dst_disk_format { my ($storecfg, $storeid, $src_volid, $format) = @_; diff --git a/src/PVE/QemuServer/DriveDevice.pm b/src/PVE/QemuServer/DriveDevice.pm new file mode 100644 index 00000000..bb884cca --- /dev/null +++ b/src/PVE/QemuServer/DriveDevice.pm @@ -0,0 +1,187 @@ +package PVE::QemuServer::DriveDevice; + +use strict; +use warnings; + +use URI::Escape; + +use PVE::QemuServer::Drive qw (drive_is_cdrom); +use PVE::QemuServer::Helpers qw(kvm_user_version min_version); +use PVE::QemuServer::Machine; +use PVE::QemuServer::PCI qw(print_pci_addr); + +use base qw(Exporter); + +our @EXPORT_OK = qw( + print_drivedevice_full + scsihw_infos +); + +sub scsihw_infos { + my ($conf, $drive) = @_; + + my $maxdev = 0; + + if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) { + $maxdev = 7; + } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) { + $maxdev = 1; + } else { + $maxdev = 256; + } + + my $controller = int($drive->{index} / $maxdev); + my $controller_prefix = + ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') + ? "virtioscsi" + : "scsihw"; + + return ($maxdev, $controller, $controller_prefix); +} + +sub print_drivedevice_full { + my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_; + + my $device = ''; + my $maxdev = 0; + + my $machine_version = + PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version()); + my $has_write_cache = 1; # whether the device has a 'write-cache' option + + my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); + if ($drive->{interface} eq 'virtio') { + my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch); + $device = 'virtio-blk-pci'; + # for the switch to -blockdev, there is no blockdev for 'none' + if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { + $device .= ",drive=drive-$drive_id"; + } + $device .= ",id=${drive_id}${pciaddr}"; + $device .= ",iothread=iothread-$drive_id" if $drive->{iothread}; + } elsif ($drive->{interface} eq 'scsi') { + + my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive); + my $unit = $drive->{index} % $maxdev; + + my $device_type = + PVE::QemuServer::Drive::get_scsi_device_type($drive, $storecfg, $machine_version); + + if (!$conf->{scsihw} || $conf->{scsihw} =~ m/^lsi/ || $conf->{scsihw} eq 'pvscsi') { + $device = "scsi-$device_type,bus=$controller_prefix$controller.0,scsi-id=$unit"; + } else { + $device = "scsi-$device_type,bus=$controller_prefix$controller.0,channel=0,scsi-id=0" + . ",lun=$drive->{index}"; + } + # for the switch to -blockdev, there is no blockdev for 'none' + if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { + $device .= ",drive=drive-$drive_id"; + } + $device .= ",id=$drive_id"; + + # For the switch to -blockdev, the SCSI device ID needs to be explicitly specified. Note + # that only ide-cd and ide-hd have a 'device_id' option. + if ( + min_version($machine_version, 10, 0) && ($device_type eq 'cd' || $device_type eq 'hd') + ) { + $device .= ",device_id=drive-${drive_id}"; + } + + if ($drive->{ssd} && ($device_type eq 'block' || $device_type eq 'hd')) { + $device .= ",rotation_rate=1"; + } + $device .= ",wwn=$drive->{wwn}" if $drive->{wwn}; + + # only scsi-hd and scsi-cd support passing vendor and product information and have a + # 'write-cache' option + if ($device_type eq 'hd' || $device_type eq 'cd') { + if (my $vendor = $drive->{vendor}) { + $device .= ",vendor=$vendor"; + } + if (my $product = $drive->{product}) { + $device .= ",product=$product"; + } + + $has_write_cache = 1; + } else { + $has_write_cache = 0; + } + + } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') { + my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2; + my $controller = int($drive->{index} / $maxdev); + my $unit = $drive->{index} % $maxdev; + + # machine type q35 only supports unit=0 for IDE rather than 2 units. This wasn't handled + # correctly before, so e.g. index=2 was mapped to controller=1,unit=0 rather than + # controller=2,unit=0. Note that odd indices never worked, as they would be mapped to + # unit=1, so to keep backwards compat for migration, it suffices to keep even ones as they + # were before. Move odd ones up by 2 where they don't clash. + if (PVE::QemuServer::Machine::machine_type_is_q35($conf) && $drive->{interface} eq 'ide') { + $controller += 2 * ($unit % 2); + $unit = 0; + } + + my $device_type = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd"; + + # With ide-hd, the inserted block node needs to be marked as writable too, but -blockdev + # will complain if it's marked as writable but the actual backing device is read-only (e.g. + # read-only base LV). IDE/SATA do not support being configured as read-only, the most + # similar is using ide-cd instead of ide-hd, with most of the code and configuration shared + # in QEMU. Since a template is never actually started, the front-end device is never + # accessed. The backup only accesses the inserted block node, so it does not matter for the + # backup if the type is 'ide-cd' instead. + $device_type = 'cd' if $conf->{template}; + + $device = "ide-$device_type"; + if ($drive->{interface} eq 'ide') { + $device .= ",bus=ide.$controller,unit=$unit"; + } else { + $device .= ",bus=ahci$controller.$unit"; + } + if (!min_version($machine_version, 10, 0) || $drive->{file} ne 'none') { + $device .= ",drive=drive-$drive_id"; + } + $device .= ",id=$drive_id"; + + if ($device_type eq 'hd') { + if (my $model = $drive->{model}) { + $model = URI::Escape::uri_unescape($model); + $device .= ",model=$model"; + } + if ($drive->{ssd}) { + $device .= ",rotation_rate=1"; + } + } + $device .= ",wwn=$drive->{wwn}" if $drive->{wwn}; + } elsif ($drive->{interface} eq 'usb') { + die "implement me"; + # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 + } else { + die "unsupported interface type"; + } + + $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex}; + + if (my $serial = $drive->{serial}) { + $serial = URI::Escape::uri_unescape($serial); + $device .= ",serial=$serial"; + } + + if (min_version($machine_version, 10, 0)) { # for the switch to -blockdev + if (!drive_is_cdrom($drive) && $has_write_cache) { + my $write_cache = 'on'; + if (my $cache = $drive->{cache}) { + $write_cache = 'off' if $cache eq 'writethrough' || $cache eq 'directsync'; + } + $device .= ",write-cache=$write_cache"; + } + for my $o (qw(rerror werror)) { + $device .= ",$o=$drive->{$o}" if defined($drive->{$o}); + } + } + + return $device; +} + +1; diff --git a/src/PVE/QemuServer/Makefile b/src/PVE/QemuServer/Makefile index 23c136bc..c5639589 100644 --- a/src/PVE/QemuServer/Makefile +++ b/src/PVE/QemuServer/Makefile @@ -10,6 +10,7 @@ SOURCES=Agent.pm \ CPUConfig.pm \ DBusVMState.pm \ Drive.pm \ + DriveDevice.pm \ Helpers.pm \ ImportDisk.pm \ Machine.pm \ From 2af6b683010b89d2244144ee1ecd8d25a5e6e72d Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 2 Oct 2025 13:43:30 +0200 Subject: [PATCH 57/79] drive device: precise arguments for scsihw_infos() helper Avoid passing in the whole config and whole drive to a helper that requires only very specific information. Signed-off-by: Fiona Ebner --- src/PVE/QemuServer.pm | 7 ++++--- src/PVE/QemuServer/DriveDevice.pm | 13 +++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 00b92b51..122850d5 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3611,7 +3611,8 @@ sub config_to_command { if ($drive->{interface} eq 'scsi') { - my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive); + my ($maxdev, $controller, $controller_prefix) = + scsihw_infos($conf->{scsihw}, $drive->{index}); die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n" @@ -4185,7 +4186,7 @@ sub qemu_devicedelverify { sub qemu_findorcreatescsihw { my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_; - my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device); + my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf->{scsihw}, $device->{index}); my $scsihwid = "$controller_prefix$controller"; my $devices_list = vm_devices_list($vmid); @@ -4207,7 +4208,7 @@ sub qemu_deletescsihw { return 1; } - my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device); + my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf->{scsihw}, $device->{index}); my $devices_list = vm_devices_list($vmid); foreach my $opt (keys %{$devices_list}) { diff --git a/src/PVE/QemuServer/DriveDevice.pm b/src/PVE/QemuServer/DriveDevice.pm index bb884cca..ca230ed3 100644 --- a/src/PVE/QemuServer/DriveDevice.pm +++ b/src/PVE/QemuServer/DriveDevice.pm @@ -18,21 +18,21 @@ our @EXPORT_OK = qw( ); sub scsihw_infos { - my ($conf, $drive) = @_; + my ($scsihw, $drive_index) = @_; my $maxdev = 0; - if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) { + if (!$scsihw || ($scsihw =~ m/^lsi/)) { $maxdev = 7; - } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) { + } elsif ($scsihw && ($scsihw eq 'virtio-scsi-single')) { $maxdev = 1; } else { $maxdev = 256; } - my $controller = int($drive->{index} / $maxdev); + my $controller = int($drive_index / $maxdev); my $controller_prefix = - ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') + ($scsihw && $scsihw eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw"; @@ -61,7 +61,8 @@ sub print_drivedevice_full { $device .= ",iothread=iothread-$drive_id" if $drive->{iothread}; } elsif ($drive->{interface} eq 'scsi') { - my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive); + my ($maxdev, $controller, $controller_prefix) = + scsihw_infos($conf->{scsihw}, $drive->{index}); my $unit = $drive->{index} % $maxdev; my $device_type = From 66e46cb6700146d6fd8fca4217e8179e976b2124 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 15:25:58 +0200 Subject: [PATCH 58/79] api: agent: improve module imports Order module import according to the style guide and add missing PVE::QemuConfig import. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250909132613.96402-2-f.ebner@proxmox.com --- src/PVE/API2/Qemu/Agent.pm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PVE/API2/Qemu/Agent.pm b/src/PVE/API2/Qemu/Agent.pm index a083ed62..de36ce1e 100644 --- a/src/PVE/API2/Qemu/Agent.pm +++ b/src/PVE/API2/Qemu/Agent.pm @@ -3,13 +3,16 @@ package PVE::API2::Qemu::Agent; use strict; use warnings; -use PVE::RESTHandler; +use JSON; +use MIME::Base64 qw(encode_base64 decode_base64); + use PVE::JSONSchema qw(get_standard_option); +use PVE::RESTHandler; + +use PVE::QemuConfig; use PVE::QemuServer; use PVE::QemuServer::Agent qw(agent_cmd check_agent_error); use PVE::QemuServer::Monitor qw(mon_cmd); -use MIME::Base64 qw(encode_base64 decode_base64); -use JSON; use base qw(PVE::RESTHandler); From 480af34c6578961c584c8b3ae4476eedd0b140b1 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 15:25:59 +0200 Subject: [PATCH 59/79] qmp client: remove erroneous comment This is most likely a left-over from copy-pasting from an example in the 'IO::Multiplex' man page. In particular, the method is not called every second. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250909132613.96402-3-f.ebner@proxmox.com --- src/PVE/QMPClient.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PVE/QMPClient.pm b/src/PVE/QMPClient.pm index 7b19be9d..68ce0edb 100644 --- a/src/PVE/QMPClient.pm +++ b/src/PVE/QMPClient.pm @@ -479,7 +479,6 @@ sub mux_input { &$check_queue($self); } -# This gets called every second to update player info, etc... sub mux_timeout { my ($self, $mux, $fh) = @_; From 82fd82c16598d0092a637527ed2ef08c36c9d9a3 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 15:26:00 +0200 Subject: [PATCH 60/79] agent: implement fsfreeze helper to better handle lost commands As reported in the enterprise support, it can happen that a guest agent command is read, but then the guest agent never sends an answer, because the service in the guest is stopped/killed. For example, if a guest reboot happens before the command can be successfully executed. This is usually not problematic, but the fsfreeze-freeze command has a timeout of 1 hour, so the guest agent socket would be blocked for that amount of time, waiting on a command that is not being executed anymore. Use a lower timeout for the initial fsfreeze-freeze command, and issue an fsfreeze-status command afterwards, which will return immediately if the fsfreeze-freeze command already finished, and which will be queued if not. This is used as a proxy to determine whether the fsfreeze-freeze command is still running and to check whether it was successful. Using a too low timeout would mean stuffing/queuing many fsfreeze-status commands while the guest agent might still be busy actually doing the freeze. In total, fsfreeze-freeze is still allowed to take 1 hour, but the time the socket is blocked after a "lost command" is at most 10 minutes. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250909132613.96402-4-f.ebner@proxmox.com --- src/PVE/QMPClient.pm | 4 ++ src/PVE/QemuConfig.pm | 4 +- src/PVE/QemuServer/Agent.pm | 68 ++++++++++++++++++++++++++++++++++ src/PVE/QemuServer/BlockJob.pm | 2 +- src/PVE/VZDump/QemuServer.pm | 4 +- 5 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/PVE/QMPClient.pm b/src/PVE/QMPClient.pm index 68ce0edb..1935a336 100644 --- a/src/PVE/QMPClient.pm +++ b/src/PVE/QMPClient.pm @@ -110,6 +110,8 @@ sub cmd { } elsif ($cmd->{execute} =~ m/^(eject|change)/) { $timeout = 60; # note: cdrom mount command is slow } elsif ($cmd->{execute} eq 'guest-fsfreeze-freeze') { + # consider using the guest_fsfreeze() helper in Agent.pm + # # freeze syncs all guest FS, if we kill it it stays in an unfreezable # locked state with high probability, so use an generous timeout $timeout = 60 * 60; # 1 hour @@ -158,6 +160,7 @@ sub cmd { if (defined($queue_info->{error})) { die "VM $vmid qmp command '$cmd->{execute}' failed - $queue_info->{error}" if !$noerr; $result = { error => $queue_info->{error} }; + $result->{'error-is-timeout'} = 1 if $queue_info->{'error-is-timeout'}; } return $result; @@ -484,6 +487,7 @@ sub mux_timeout { if (my $queue_info = &$lookup_queue_info($self, $fh)) { $queue_info->{error} = "got timeout\n"; + $queue_info->{'error-is-timeout'} = 1; $self->{mux}->inbuffer($fh, ''); # clear to avoid warnings } diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index d0844c4c..97b2e8a5 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -312,8 +312,8 @@ sub __snapshot_freeze { eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); }; warn "guest-fsfreeze-thaw problems - $@" if $@; } else { - eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); }; - warn "guest-fsfreeze-freeze problems - $@" if $@; + eval { PVE::QemuServer::Agent::guest_fsfreeze($vmid); }; + warn $@ if $@; } } diff --git a/src/PVE/QemuServer/Agent.pm b/src/PVE/QemuServer/Agent.pm index ee48e83e..9ec9c1de 100644 --- a/src/PVE/QemuServer/Agent.pm +++ b/src/PVE/QemuServer/Agent.pm @@ -131,4 +131,72 @@ sub qemu_exec_status { return $res; } +=head3 guest_fsfreeze + + guest_fsfreeze($vmid); + +Freeze the file systems of the guest C<$vmid>. Check that the guest agent is enabled and running +before calling this function. Dies if the file systems cannot be frozen. + +With C, it can happen that a guest agent command is read, but then the guest agent never +sends an answer, because the service in the guest is stopped/killed. For example, if a guest reboot +happens before the command can be successfully executed. This is usually not problematic, but the +fsfreeze-freeze command should use a timeout of 1 hour, so the guest agent socket would be blocked +for that amount of time, waiting on a command that is not being executed anymore. + +This function uses a lower timeout for the initial fsfreeze-freeze command, and issues an +fsfreeze-status command afterwards, which will return immediately if the fsfreeze-freeze command +already finished, and which will be queued if not. This is used as a proxy to determine whether the +fsfreeze-freeze command is still running and to check whether it was successful. Using a too low +timeout would mean stuffing/queuing many fsfreeze-status commands while the guest agent might still +be busy actually doing the freeze. In total, fsfreeze-freeze is still allowed to take 1 hour, but +the time the socket is blocked after a lost command is at most 10 minutes. + +=cut + +sub guest_fsfreeze { + my ($vmid) = @_; + + my $timeout = 10 * 60; + + my $result = eval { + PVE::QemuServer::Monitor::mon_cmd($vmid, 'guest-fsfreeze-freeze', timeout => $timeout); + }; + if ($result && ref($result) eq 'HASH' && $result->{error}) { + my $error = $result->{error}->{desc} // 'unknown'; + die "unable to freeze guest fs - $error\n"; + } elsif (defined($result)) { + return; # command successful + } + + my $status; + eval { + my ($i, $last_iteration) = (0, 5); + while ($i < $last_iteration && !defined($status)) { + print "still waiting on guest fs freeze - timeout in " + . ($timeout * ($last_iteration - $i) / 60) + . " minutes\n"; + $i++; + + $status = PVE::QemuServer::Monitor::mon_cmd( + $vmid, 'guest-fsfreeze-status', + timeout => $timeout, + noerr => 1, + ); + + if ($status && ref($status) eq 'HASH' && $status->{'error-is-timeout'}) { + $status = undef; + } else { + check_agent_error($status, 'unknown error'); + } + } + if (!defined($status)) { + die "timeout after " . ($timeout * ($last_iteration + 1) / 60) . " minutes\n"; + } + }; + die "querying status after freezing guest fs failed - $@" if $@; + + die "unable to freeze guest fs - unexpected status '$status'\n" if $status ne 'frozen'; +} + 1; diff --git a/src/PVE/QemuServer/BlockJob.pm b/src/PVE/QemuServer/BlockJob.pm index 633c0b34..506010e1 100644 --- a/src/PVE/QemuServer/BlockJob.pm +++ b/src/PVE/QemuServer/BlockJob.pm @@ -165,7 +165,7 @@ sub qemu_drive_mirror_monitor { my $agent_running = $qga && qga_check_running($vmid); if ($agent_running) { print "freeze filesystem\n"; - eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); }; + eval { PVE::QemuServer::Agent::guest_fsfreeze($vmid); }; warn $@ if $@; } else { print "suspend vm\n"; diff --git a/src/PVE/VZDump/QemuServer.pm b/src/PVE/VZDump/QemuServer.pm index 5b94c369..23ac74f7 100644 --- a/src/PVE/VZDump/QemuServer.pm +++ b/src/PVE/VZDump/QemuServer.pm @@ -1103,10 +1103,10 @@ sub qga_fs_freeze { } $self->loginfo("issuing guest-agent 'fs-freeze' command"); - eval { mon_cmd($vmid, "guest-fsfreeze-freeze") }; + eval { PVE::QemuServer::Agent::guest_fsfreeze($vmid); }; $self->logerr($@) if $@; - return 1; # even on mon command error, ensure we always thaw again + return 1; # even on error, ensure we always thaw again } # only call if fs_freeze return 1 From 65c834d980e9f274f7bfe54ac3af706b82a7eefe Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 15:26:01 +0200 Subject: [PATCH 61/79] agent: prefer usage of get_qga_key() helper Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250909132613.96402-5-f.ebner@proxmox.com --- src/PVE/QemuConfig.pm | 2 +- src/PVE/QemuMigrate.pm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index 97b2e8a5..91eb0076 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -297,7 +297,7 @@ sub __snapshot_check_freeze_needed { return ( $running, $running - && PVE::QemuServer::parse_guest_agent($config)->{enabled} + && PVE::QemuServer::get_qga_key($config, 'enabled') && PVE::QemuServer::Agent::qga_check_running($vmid), ); } else { diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 7093c41e..40988e3e 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -1723,7 +1723,7 @@ sub phase3_cleanup { if ( $self->{storage_migration} - && PVE::QemuServer::parse_guest_agent($conf)->{fstrim_cloned_disks} + && PVE::QemuServer::get_qga_key($conf, 'fstrim_cloned_disks') && $self->{running} ) { if (!$self->{vm_was_paused}) { From 87fa886ffed4532018c6dd945542598703a1af19 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Tue, 9 Sep 2025 15:26:02 +0200 Subject: [PATCH 62/79] agent: move guest agent format and parsing to agent module Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250909132613.96402-6-f.ebner@proxmox.com --- src/PVE/API2/Qemu.pm | 4 +-- src/PVE/QemuConfig.pm | 2 +- src/PVE/QemuMigrate.pm | 3 +- src/PVE/QemuServer.pm | 54 ++---------------------------------- src/PVE/QemuServer/Agent.pm | 54 ++++++++++++++++++++++++++++++++++++ src/PVE/VZDump/QemuServer.pm | 3 +- 6 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 8bcd16b3..7fced6c6 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -3330,7 +3330,7 @@ __PACKAGE__->register_method({ $status->{spice} = 1 if $spice; $status->{clipboard} = $vga->{clipboard}; } - $status->{agent} = 1 if PVE::QemuServer::get_qga_key($conf, 'enabled'); + $status->{agent} = 1 if PVE::QemuServer::Agent::get_qga_key($conf, 'enabled'); return $status; }, @@ -4798,7 +4798,7 @@ __PACKAGE__->register_method({ PVE::QemuConfig->write_config($vmid, $conf); - my $do_trim = PVE::QemuServer::get_qga_key($conf, 'fstrim_cloned_disks'); + my $do_trim = PVE::QemuServer::Agent::get_qga_key($conf, 'fstrim_cloned_disks'); if ($running && $do_trim && PVE::QemuServer::Agent::qga_check_running($vmid)) { eval { mon_cmd($vmid, "guest-fstrim") }; } diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index 91eb0076..bb469197 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -297,7 +297,7 @@ sub __snapshot_check_freeze_needed { return ( $running, $running - && PVE::QemuServer::get_qga_key($config, 'enabled') + && PVE::QemuServer::Agent::get_qga_key($config, 'enabled') && PVE::QemuServer::Agent::qga_check_running($vmid), ); } else { diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 40988e3e..51d9068e 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -27,6 +27,7 @@ use PVE::Tunnel; use PVE::QemuConfig; use PVE::QemuMigrate::Helpers; +use PVE::QemuServer::Agent; use PVE::QemuServer::BlockJob; use PVE::QemuServer::CPUConfig; use PVE::QemuServer::Drive qw(checked_volume_format); @@ -1723,7 +1724,7 @@ sub phase3_cleanup { if ( $self->{storage_migration} - && PVE::QemuServer::get_qga_key($conf, 'fstrim_cloned_disks') + && PVE::QemuServer::Agent::get_qga_key($conf, 'fstrim_cloned_disks') && $self->{running} ) { if (!$self->{vm_was_paused}) { diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 122850d5..d12bb8d2 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -53,7 +53,7 @@ use PVE::QMPClient; use PVE::QemuConfig; use PVE::QemuConfig::NoWrite; use PVE::QemuMigrate::Helpers; -use PVE::QemuServer::Agent qw(qga_check_running); +use PVE::QemuServer::Agent qw(get_qga_key parse_guest_agent qga_check_running); use PVE::QemuServer::Blockdev; use PVE::QemuServer::BlockJob; use PVE::QemuServer::Helpers @@ -148,35 +148,6 @@ my $watchdog_fmt = { }; PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt); -my $agent_fmt = { - enabled => { - description => - "Enable/disable communication with a QEMU Guest Agent (QGA) running in the VM.", - type => 'boolean', - default => 0, - default_key => 1, - }, - fstrim_cloned_disks => { - description => "Run fstrim after moving a disk or migrating the VM.", - type => 'boolean', - optional => 1, - default => 0, - }, - 'freeze-fs-on-backup' => { - description => "Freeze/thaw guest filesystems on backup for consistency.", - type => 'boolean', - optional => 1, - default => 1, - }, - type => { - description => "Select the agent type", - type => 'string', - default => 'virtio', - optional => 1, - enum => [qw(virtio isa)], - }, -}; - my $vga_fmt = { type => { description => "Select the VGA type. Using type 'cirrus' is not recommended.", @@ -472,7 +443,7 @@ EODESC description => "Enable/disable communication with the QEMU Guest Agent and its properties.", type => 'string', - format => $agent_fmt, + format => $PVE::QemuServer::Agent::agent_fmt, }, kvm => { optional => 1, @@ -1648,27 +1619,6 @@ sub parse_watchdog { return $res; } -sub parse_guest_agent { - my ($conf) = @_; - - return {} if !defined($conf->{agent}); - - my $res = eval { parse_property_string($agent_fmt, $conf->{agent}) }; - warn $@ if $@; - - # if the agent is disabled ignore the other potentially set properties - return {} if !$res->{enabled}; - return $res; -} - -sub get_qga_key { - my ($conf, $key) = @_; - return undef if !defined($conf->{agent}); - - my $agent = parse_guest_agent($conf); - return $agent->{$key}; -} - sub parse_vga { my ($value) = @_; diff --git a/src/PVE/QemuServer/Agent.pm b/src/PVE/QemuServer/Agent.pm index 9ec9c1de..5d88b7bd 100644 --- a/src/PVE/QemuServer/Agent.pm +++ b/src/PVE/QemuServer/Agent.pm @@ -6,6 +6,8 @@ use warnings; use JSON; use MIME::Base64 qw(decode_base64 encode_base64); +use PVE::JSONSchema; + use PVE::QemuServer::Helpers; use PVE::QemuServer::Monitor; @@ -14,9 +16,61 @@ use base 'Exporter'; our @EXPORT_OK = qw( check_agent_error agent_cmd + get_qga_key + parse_guest_agent qga_check_running ); +our $agent_fmt = { + enabled => { + description => + "Enable/disable communication with a QEMU Guest Agent (QGA) running in the VM.", + type => 'boolean', + default => 0, + default_key => 1, + }, + fstrim_cloned_disks => { + description => "Run fstrim after moving a disk or migrating the VM.", + type => 'boolean', + optional => 1, + default => 0, + }, + 'freeze-fs-on-backup' => { + description => "Freeze/thaw guest filesystems on backup for consistency.", + type => 'boolean', + optional => 1, + default => 1, + }, + type => { + description => "Select the agent type", + type => 'string', + default => 'virtio', + optional => 1, + enum => [qw(virtio isa)], + }, +}; + +sub parse_guest_agent { + my ($conf) = @_; + + return {} if !defined($conf->{agent}); + + my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $conf->{agent}) }; + warn $@ if $@; + + # if the agent is disabled ignore the other potentially set properties + return {} if !$res->{enabled}; + return $res; +} + +sub get_qga_key { + my ($conf, $key) = @_; + return undef if !defined($conf->{agent}); + + my $agent = parse_guest_agent($conf); + return $agent->{$key}; +} + sub qga_check_running { my ($vmid, $nowarn) = @_; diff --git a/src/PVE/VZDump/QemuServer.pm b/src/PVE/VZDump/QemuServer.pm index 23ac74f7..1addfa24 100644 --- a/src/PVE/VZDump/QemuServer.pm +++ b/src/PVE/VZDump/QemuServer.pm @@ -1096,7 +1096,8 @@ sub qga_fs_freeze { return; } - my $freeze = PVE::QemuServer::get_qga_key($self->{vmlist}->{$vmid}, 'freeze-fs-on-backup') // 1; + my $freeze = + PVE::QemuServer::Agent::get_qga_key($self->{vmlist}->{$vmid}, 'freeze-fs-on-backup') // 1; if (!$freeze) { $self->loginfo("skipping guest-agent 'fs-freeze', disabled in VM options"); return; From 5595b5af806a328778e94b05776ee5c6edd56d74 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:24:46 +0200 Subject: [PATCH 63/79] dbus vmstate: add missing includes Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250929122529.90484-2-f.ebner@proxmox.com --- src/PVE/QemuServer/DBusVMState.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PVE/QemuServer/DBusVMState.pm b/src/PVE/QemuServer/DBusVMState.pm index 36ff8168..a72d6dd2 100644 --- a/src/PVE/QemuServer/DBusVMState.pm +++ b/src/PVE/QemuServer/DBusVMState.pm @@ -3,10 +3,15 @@ package PVE::QemuServer::DBusVMState; use strict; use warnings; +use Net::DBus; +use Net::DBus::RemoteService; + use PVE::SafeSyslog; use PVE::Systemd; use PVE::Tools; +use PVE::QemuServer::Helpers; + use constant { DBUS_VMSTATE_EXE => '/usr/libexec/qemu-server/dbus-vmstate', }; From 26717ab3b8796c6f4aa0eedd9a7537091ed73d17 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:24:47 +0200 Subject: [PATCH 64/79] migration: conntrack: work around systemd issue where scope for VM might become blocked Because of a systemd issue [0], when a service that's 'partOf' a scope fails, the scope itself might end up being left-over, even after all processes in the scope exit. In particular, this can happen for the '$vmid.scope' when the 'pve-dbus-vmstate@$vmid.service' fails. Doing a 'reset-failed' of the failed 'partOf' service leads to the left-over scope being cleaned up too. Without that users in that situation would get a difficult-to-make-sense-of "timeout waiting on systemd" error message. [0]: https://github.com/systemd/systemd/issues/39141 Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20250929122529.90484-3-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index d12bb8d2..9f35de2e 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5613,6 +5613,12 @@ sub vm_start_nolock { } my %silence_std_outs = (outfunc => sub { }, errfunc => sub { }); + eval { # See systemd GH #39141, need to reset failed PartOf units too, or scope might be blocked + run_command( + ['/bin/systemctl', 'reset-failed', "pve-dbus-vmstate\@$vmid.service"], + %silence_std_outs, + ); + }; eval { run_command(['/bin/systemctl', 'reset-failed', "$vmid.scope"], %silence_std_outs) }; eval { run_command(['/bin/systemctl', 'stop', "$vmid.scope"], %silence_std_outs) }; # Issues with the above 'stop' not being fully completed are extremely rare, a very low From 14c57934ed59472b8b0751c06838773ee7c86969 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Wed, 1 Oct 2025 17:01:08 +0200 Subject: [PATCH 65/79] fix #6828: remote migration: bump timeout for writing configuration to accommodate volume activation The 'config' command will lead to volume activation being done for the referenced volumes. This is because the 'config' handler in the mtunnel API endpoint calls into the update_vm_api() function, which uses the create_disks() function, which is also used for existing disks. In create_disks(), each volume is activated to do an existence/basic sanity check by querying its size. There is no requirement to be fast when handling the 'config' command during remote migration. Since there could be many disks for a given VM, allow for up to 2 minutes instead of just 10 seconds. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20251001150118.136976-2-f.ebner@proxmox.com --- src/PVE/QemuMigrate.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 51d9068e..78954c20 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -923,7 +923,7 @@ sub phase1_remote { 'firewall-config' => $fw_conf_str, }; - PVE::Tunnel::write_tunnel($self->{tunnel}, 10, 'config', $params); + PVE::Tunnel::write_tunnel($self->{tunnel}, 120, 'config', $params); } sub phase1_cleanup { From cd82e3f270d9310076da248c3f699c2a460d9628 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 3 Oct 2025 12:33:10 +0200 Subject: [PATCH 66/79] fix #6882: backup provider api: fix backup with TPM state by correctly generating node name The backup-access API in QEMU expects the '-backup' suffix to be present for the TPM state fleecing image too. This is a regression of the switch to using blockdev for fleecing images with commit f92c1fa0 ("backup: use blockdev for fleecing images"). Add special handling to the fleecing_node_name() helper to fix it. Fleecing backups to native plugins do not use a dedicated image for the TPM state, so this only affected the backup provider API. Fixes: f92c1fa0 ("backup: use blockdev for fleecing images") Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20251003103319.44974-2-f.ebner@proxmox.com --- src/PVE/QemuServer/Blockdev.pm | 6 ++++-- src/PVE/VZDump/QemuServer.pm | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 8e6749e8..8fa5eb51 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -43,7 +43,9 @@ my sub tpm_backup_node_name { } my sub fleecing_node_name { - my ($type, $drive_id) = @_; + my ($type, $drive_id, $options) = @_; + + $drive_id .= '-backup' if $options->{'tpm-backup'}; if ($type eq 'fmt') { return "drive-$drive_id-fleecing"; # this is the top node for fleecing @@ -114,7 +116,7 @@ sub get_block_info { my sub get_node_name { my ($type, $drive_id, $volid, $options) = @_; - return fleecing_node_name($type, $drive_id) if $options->{fleecing}; + return fleecing_node_name($type, $drive_id, $options) if $options->{fleecing}; return tpm_backup_node_name($type, $drive_id) if $options->{'tpm-backup'}; my $snap = $options->{'snapshot-name'}; diff --git a/src/PVE/VZDump/QemuServer.pm b/src/PVE/VZDump/QemuServer.pm index 1addfa24..1407e177 100644 --- a/src/PVE/VZDump/QemuServer.pm +++ b/src/PVE/VZDump/QemuServer.pm @@ -659,6 +659,7 @@ my sub attach_fleecing_images { }; my $options = { 'fleecing' => 1 }; + $options->{'tpm-backup'} = 1 if $interface eq 'tpmstate'; # Specify size explicitly, to make it work if storage backend rounded up size for # fleecing image when allocating. $options->{size} = $di->{'block-node-size'} if $format eq 'raw'; From 33c0169fefe6a7d5a011c2539df59356674335e2 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Fri, 3 Oct 2025 12:33:11 +0200 Subject: [PATCH 67/79] backup: fleecing: avoid warning when querying block node size for TPM state Currently, there only is a warning that the fallback, being the size queried from the storage, is used. This should work in all cases, but there are plans for supporting TPM state as a FUSE/NBD export from an underlying qcow2 image where it might still work, but the correspondence of size between the attached block node in QEMU and the storage layer already becomes much more blurry. Avoid the warning and future-proof by also querying the size for the TPM state directly from the attached block node in QEMU. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/all/20251003103319.44974-3-f.ebner@proxmox.com --- src/PVE/VZDump/QemuServer.pm | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/PVE/VZDump/QemuServer.pm b/src/PVE/VZDump/QemuServer.pm index 1407e177..dd789652 100644 --- a/src/PVE/VZDump/QemuServer.pm +++ b/src/PVE/VZDump/QemuServer.pm @@ -1129,9 +1129,22 @@ sub query_block_node_sizes { for my $diskinfo ($disks->@*) { my $drive_key = $diskinfo->{virtdev}; - $drive_key .= "-backup" if $drive_key eq 'tpmstate0'; - my $block_node_size = - eval { $block_info->{$drive_key}->{inserted}->{image}->{'virtual-size'}; }; + + my $block_node_size; + if ($drive_key eq 'tpmstate0') { + # There is no front-end device for TPM state, so it's not included in the result of + # get_block_info(). Note that it is always attached with the same explicit node name. + my $named_block_node_info = mon_cmd($vmid, 'query-named-block-nodes'); + for my $info ($named_block_node_info->@*) { + next if $info->{'node-name'} ne 'drive-tpmstate0-backup'; + $block_node_size = $info->{image}->{'virtual-size'}; + last; + } + } else { + $block_node_size = + eval { $block_info->{$drive_key}->{inserted}->{image}->{'virtual-size'}; }; + } + if (!$block_node_size) { $self->loginfo( "could not determine block node size of drive '$drive_key' - using fallback"); From b795c0a39095b72ceb2fce5f9d5bb78777b1b294 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:56:46 +0200 Subject: [PATCH 68/79] tests: cfg2cmd: add tests for startdate parameter and disabled time drift fix No test currently cover these settings. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-2-f.ebner@proxmox.com --- src/test/cfg2cmd/startdate-l26.conf | 3 +++ src/test/cfg2cmd/startdate-l26.conf.cmd | 27 +++++++++++++++++++++++ src/test/cfg2cmd/startdate-win11.conf | 4 ++++ src/test/cfg2cmd/startdate-win11.conf.cmd | 26 ++++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/test/cfg2cmd/startdate-l26.conf create mode 100644 src/test/cfg2cmd/startdate-l26.conf.cmd create mode 100644 src/test/cfg2cmd/startdate-win11.conf create mode 100644 src/test/cfg2cmd/startdate-win11.conf.cmd diff --git a/src/test/cfg2cmd/startdate-l26.conf b/src/test/cfg2cmd/startdate-l26.conf new file mode 100644 index 00000000..eb35a971 --- /dev/null +++ b/src/test/cfg2cmd/startdate-l26.conf @@ -0,0 +1,3 @@ +# TEST: Simple test for startdate parameter with Linux +ostype: l26 +startdate: 2006-06-17T16:01:21 diff --git a/src/test/cfg2cmd/startdate-l26.conf.cmd b/src/test/cfg2cmd/startdate-l26.conf.cmd new file mode 100644 index 00000000..9a3ba21e --- /dev/null +++ b/src/test/cfg2cmd/startdate-l26.conf.cmd @@ -0,0 +1,27 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -rtc 'base=2006-06-17T16:01:21' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/startdate-win11.conf b/src/test/cfg2cmd/startdate-win11.conf new file mode 100644 index 00000000..ac5dcbcf --- /dev/null +++ b/src/test/cfg2cmd/startdate-win11.conf @@ -0,0 +1,4 @@ +# TEST: Simple test for startdate parameter with Windows and explicitly disabled time drift fix +ostype: win11 +tdf: 0 +startdate: 2020-01-11 diff --git a/src/test/cfg2cmd/startdate-win11.conf.cmd b/src/test/cfg2cmd/startdate-win11.conf.cmd new file mode 100644 index 00000000..a15dc213 --- /dev/null +++ b/src/test/cfg2cmd/startdate-win11.conf.cmd @@ -0,0 +1,26 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -global 'kvm-pit.lost_tick_policy=discard' \ + -cpu 'kvm64,enforce,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep' \ + -m 512 \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2,edid=off' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -rtc 'base=2020-01-11' \ + -machine 'hpet=off,type=pc-i440fx-5.1+pve0' From 3c46c7ddb3e3b5c16cb75dc39b8e8f78397df658 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:56:47 +0200 Subject: [PATCH 69/79] tests: add tests for non-{Linux, Windows} OS types For 'l24', use 'vga: qxl' since that is the only place where a Linux check is done not only for 'l26'. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-3-f.ebner@proxmox.com --- src/test/cfg2cmd/os-l24.conf | 3 +++ src/test/cfg2cmd/os-l24.conf.cmd | 29 ++++++++++++++++++++++++++++ src/test/cfg2cmd/os-other.conf | 2 ++ src/test/cfg2cmd/os-other.conf.cmd | 26 +++++++++++++++++++++++++ src/test/cfg2cmd/os-solaris.conf | 2 ++ src/test/cfg2cmd/os-solaris.conf.cmd | 26 +++++++++++++++++++++++++ 6 files changed, 88 insertions(+) create mode 100644 src/test/cfg2cmd/os-l24.conf create mode 100644 src/test/cfg2cmd/os-l24.conf.cmd create mode 100644 src/test/cfg2cmd/os-other.conf create mode 100644 src/test/cfg2cmd/os-other.conf.cmd create mode 100644 src/test/cfg2cmd/os-solaris.conf create mode 100644 src/test/cfg2cmd/os-solaris.conf.cmd diff --git a/src/test/cfg2cmd/os-l24.conf b/src/test/cfg2cmd/os-l24.conf new file mode 100644 index 00000000..e6c3ea70 --- /dev/null +++ b/src/test/cfg2cmd/os-l24.conf @@ -0,0 +1,3 @@ +# TEST: Simple test for Linux OS type l24 +ostype: l24 +vga: qxl diff --git a/src/test/cfg2cmd/os-l24.conf.cmd b/src/test/cfg2cmd/os-l24.conf.cmd new file mode 100644 index 00000000..45dbc7cd --- /dev/null +++ b/src/test/cfg2cmd/os-l24.conf.cmd @@ -0,0 +1,29 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'qxl-vga,id=vga,max_outputs=4,bus=pci.0,addr=0x2' \ + -device 'virtio-serial,id=spice,bus=pci.0,addr=0x9' \ + -chardev 'spicevmc,id=vdagent,name=vdagent' \ + -device 'virtserialport,chardev=vdagent,name=com.redhat.spice.0' \ + -spice 'tls-port=61000,addr=127.0.0.1,tls-ciphers=HIGH,seamless-migration=on' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/os-other.conf b/src/test/cfg2cmd/os-other.conf new file mode 100644 index 00000000..741e8afb --- /dev/null +++ b/src/test/cfg2cmd/os-other.conf @@ -0,0 +1,2 @@ +# TEST: Simple test for OS type other +ostype: other diff --git a/src/test/cfg2cmd/os-other.conf.cmd b/src/test/cfg2cmd/os-other.conf.cmd new file mode 100644 index 00000000..1f53858b --- /dev/null +++ b/src/test/cfg2cmd/os-other.conf.cmd @@ -0,0 +1,26 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 512 \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=pc+pve0' diff --git a/src/test/cfg2cmd/os-solaris.conf b/src/test/cfg2cmd/os-solaris.conf new file mode 100644 index 00000000..4684ccbb --- /dev/null +++ b/src/test/cfg2cmd/os-solaris.conf @@ -0,0 +1,2 @@ +# TEST: Simple test for OS type Solaris +ostype: solaris diff --git a/src/test/cfg2cmd/os-solaris.conf.cmd b/src/test/cfg2cmd/os-solaris.conf.cmd new file mode 100644 index 00000000..23e6987f --- /dev/null +++ b/src/test/cfg2cmd/os-solaris.conf.cmd @@ -0,0 +1,26 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'vm8006,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smp '1,sockets=1,cores=1,maxcpus=1' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep,-x2apic \ + -m 512 \ + -global 'PIIX4_PM.disable_s3=1' \ + -global 'PIIX4_PM.disable_s4=1' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=pc+pve0' From 7b6cb366bf3d2705e302a1032b60570a9b371fb1 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:56:48 +0200 Subject: [PATCH 70/79] introduce dedicated cfg2cmd module Having a dedicated Cfg2Cmd class allows having a cleaner interface by only calling into pre-defined methods. Important, global information about the VM like machine type or OS version will be recorded by the object and can be queried via methods. For now, there is only windows_version(). There will be sub-classes, each concerning a dedicated part of the configuration. The first one is for the timer. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-4-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 32 +++------- src/PVE/QemuServer/Cfg2Cmd.pm | 91 +++++++++++++++++++++++++++++ src/PVE/QemuServer/Cfg2Cmd/Makefile | 9 +++ src/PVE/QemuServer/Cfg2Cmd/Timer.pm | 37 ++++++++++++ src/PVE/QemuServer/Makefile | 2 + 5 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 src/PVE/QemuServer/Cfg2Cmd.pm create mode 100644 src/PVE/QemuServer/Cfg2Cmd/Makefile create mode 100644 src/PVE/QemuServer/Cfg2Cmd/Timer.pm diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 9f35de2e..057cea25 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -56,6 +56,7 @@ use PVE::QemuMigrate::Helpers; use PVE::QemuServer::Agent qw(get_qga_key parse_guest_agent qga_check_running); use PVE::QemuServer::Blockdev; use PVE::QemuServer::BlockJob; +use PVE::QemuServer::Cfg2Cmd; use PVE::QemuServer::Helpers qw(config_aware_timeout get_iscsi_initiator_name min_version kvm_user_version windows_version); use PVE::QemuServer::Cloudinit; @@ -3379,31 +3380,12 @@ sub config_to_command { push @$cmd, '-nographic'; } - # time drift fix - my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf}; - my $useLocaltime = $conf->{localtime}; - - if ($winversion >= 5) { # windows - $useLocaltime = 1 if !defined($conf->{localtime}); - - # use time drift fix when acpi is enabled - if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) { - $tdf = 1 if !defined($conf->{tdf}); - } - } - - if ($winversion >= 6) { - push $cmd->@*, '-global', 'kvm-pit.lost_tick_policy=discard'; - push @$machineFlags, 'hpet=off'; - } - - push @$rtcFlags, 'driftfix=slew' if $tdf; - - if ($conf->{startdate} && $conf->{startdate} ne 'now') { - push @$rtcFlags, "base=$conf->{startdate}"; - } elsif ($useLocaltime) { - push @$rtcFlags, 'base=localtime'; - } + # For now, handles only specific parts, but the final goal is to cover everything. + my $cfg2cmd = PVE::QemuServer::Cfg2Cmd->new($conf, $defaults); + my $generated = $cfg2cmd->generate(); + push $cmd->@*, '-global', $_ for ($generated->global_flags() // [])->@*; + push $machineFlags->@*, ($generated->machine_flags() // [])->@*; + push $rtcFlags->@*, ($generated->rtc_flags() // [])->@*; if ($forcecpu) { push @$cmd, '-cpu', $forcecpu; diff --git a/src/PVE/QemuServer/Cfg2Cmd.pm b/src/PVE/QemuServer/Cfg2Cmd.pm new file mode 100644 index 00000000..6b26ab23 --- /dev/null +++ b/src/PVE/QemuServer/Cfg2Cmd.pm @@ -0,0 +1,91 @@ +package PVE::QemuServer::Cfg2Cmd; + +use warnings; +use strict; + +use PVE::QemuServer::Cfg2Cmd::Timer; +use PVE::QemuServer::Helpers; + +sub new { + my ($class, $conf, $defaults) = @_; + + my $self = bless { + conf => $conf, + defaults => $defaults, + }, $class; + + my $ostype = $self->get_prop('ostype'); + $self->{'windows-version'} = PVE::QemuServer::Helpers::windows_version($ostype); + + return $self; +} + +=head3 get_prop + + my $value = $self->get_prop($prop); + +Return the configured value for the property C<$prop>. If no fallback to the default value should be +made, use C<$only_explicit>. Note that any such usage is likely an indication that the default value +is not actually a static default, but that the default depends on context. + +=cut + +sub get_prop { + my ($self, $prop, $only_explicit) = @_; + + my ($conf, $defaults) = $self->@{qw(conf defaults)}; + return $conf->{$prop} if $only_explicit; + return defined($conf->{$prop}) ? $conf->{$prop} : $defaults->{$prop}; +} + +sub add_global_flag { + my ($self, $flag) = @_; + + push $self->{'global-flags'}->@*, $flag; +} + +sub global_flags { + my ($self) = @_; + + return $self->{'global-flags'}; +} + +sub add_machine_flag { + my ($self, $flag) = @_; + + push $self->{'machine-flags'}->@*, $flag; +} + +sub machine_flags { + my ($self) = @_; + + return $self->{'machine-flags'}; +} + +sub add_rtc_flag { + my ($self, $flag) = @_; + + push $self->{'rtc-flags'}->@*, $flag; +} + +sub rtc_flags { + my ($self) = @_; + + return $self->{'rtc-flags'}; +} + +sub windows_version { + my ($self) = @_; + + return $self->{'windows-version'}; +} + +sub generate { + my ($self) = @_; + + PVE::QemuServer::Cfg2Cmd::Timer::generate($self); + + return $self; +} + +1; diff --git a/src/PVE/QemuServer/Cfg2Cmd/Makefile b/src/PVE/QemuServer/Cfg2Cmd/Makefile new file mode 100644 index 00000000..1c0ea0b2 --- /dev/null +++ b/src/PVE/QemuServer/Cfg2Cmd/Makefile @@ -0,0 +1,9 @@ +DESTDIR= +PREFIX=/usr +PERLDIR=$(PREFIX)/share/perl5 + +SOURCES=Timer.pm + +.PHONY: install +install: $(SOURCES) + for i in $(SOURCES); do install -D -m 0644 $$i $(DESTDIR)$(PERLDIR)/PVE/QemuServer/Cfg2Cmd/$$i; done diff --git a/src/PVE/QemuServer/Cfg2Cmd/Timer.pm b/src/PVE/QemuServer/Cfg2Cmd/Timer.pm new file mode 100644 index 00000000..d4b16af0 --- /dev/null +++ b/src/PVE/QemuServer/Cfg2Cmd/Timer.pm @@ -0,0 +1,37 @@ +package PVE::QemuServer::Cfg2Cmd::Timer; + +use warnings; +use strict; + +sub generate { + my ($cfg2cmd) = @_; + + my $time_drift_fix = $cfg2cmd->get_prop('tdf', 1); + my $acpi = $cfg2cmd->get_prop('acpi'); + my $localtime = $cfg2cmd->get_prop('localtime', 1); + my $startdate = $cfg2cmd->get_prop('startdate'); + + if ($cfg2cmd->windows_version() >= 5) { # windows + $localtime = 1 if !defined($localtime); + + # use time drift fix when acpi is enabled, but prefer explicitly set value + $time_drift_fix = 1 if $acpi && !defined($time_drift_fix); + } + + if ($cfg2cmd->windows_version() >= 6) { + $cfg2cmd->add_global_flag('kvm-pit.lost_tick_policy=discard'); + $cfg2cmd->add_machine_flag('hpet=off'); + } + + $cfg2cmd->add_rtc_flag('driftfix=slew') if $time_drift_fix; + + if ($startdate ne 'now') { + $cfg2cmd->add_rtc_flag("base=$startdate"); + } elsif ($localtime) { + $cfg2cmd->add_rtc_flag('base=localtime'); + } + + return; +} + +1; diff --git a/src/PVE/QemuServer/Makefile b/src/PVE/QemuServer/Makefile index c5639589..63c8d77c 100644 --- a/src/PVE/QemuServer/Makefile +++ b/src/PVE/QemuServer/Makefile @@ -5,6 +5,7 @@ PERLDIR=$(PREFIX)/share/perl5 SOURCES=Agent.pm \ Blockdev.pm \ BlockJob.pm \ + Cfg2Cmd.pm \ CGroup.pm \ Cloudinit.pm \ CPUConfig.pm \ @@ -31,3 +32,4 @@ SOURCES=Agent.pm \ .PHONY: install install: $(SOURCES) for i in $(SOURCES); do install -D -m 0644 $$i $(DESTDIR)$(PERLDIR)/PVE/QemuServer/$$i; done + $(MAKE) -C Cfg2Cmd install From dcaf59736b34201989c42a2be102a117d508ee1b Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:56:49 +0200 Subject: [PATCH 71/79] config: schema: define default OS type Like this, the Cfg2Cmd module can fill in the default and only needs to check for definedness once. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-5-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 057cea25..f1025cfa 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -348,6 +348,7 @@ my $confdesc = { type => 'string', # NOTE: When extending, also consider extending `%guest_types` in `Import/ESXi.pm`. enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)], + default => 'other', description => "Specify guest operating system.", verbose_description => < Date: Mon, 29 Sep 2025 14:56:50 +0200 Subject: [PATCH 72/79] cfg2cmd: turn off hpet for Linux VMs running at least kernel 2.6 and machine type >= 10.1 Recent enough Linux versions already use 'kvm-clock' rather than 'hpet' as the default clock source [0][1]. Changes in QEMU [2] led to slightly increased CPU usage when using hpet [3][4]: > the timer must be kept running even if not enabled, in > order to set the ISR flag, so writes to HPET_TN_CFG must > not call hpet_del_timer() Upstream suggested to not use hpet if possible [5][6]: > That said, if you can disable the HPET timer by default without > problems with e.g. live migration I strongly suggest you do. And in > the mean time you can also revert these patches, they were actually > reported as bugs but it's not clear what guest OS was affected. > No, the bug reports are really just for corner cases and there are no > huge issues. However, both Linux and Windows give the HPET a > relatively high priority that it probably does not deserve. :) There were more changes in QEMU, so it would require more reverts. Thus, disable the timer. People having a Linux VM pinned to an older machine version or using other os types will see the increased usage again if installing the new QEMU 10.1 binary, but that seems like a fair trade-off for reducing CPU load for everybody else and being able to move forward. The is_linux() helper does not include the 'l24' os type by default, because all except one existing checks as well as the newly introduced check are specifically for 'l26' and most future features are not worth considering for 'l24' either. Users of Linux 2.6.x before v2.6.26 might need to pin the machine version or manually enable hpet if they want to continue using HPET. Otherwise, there is acpi_pm since v2.6.18 that should be automatically picked. [0]: /sys/devices/system/clocksource/clocksource0/current_clocksource [1]: Kernel commit 790c73f6289a ("x86: KVM guest: paravirtualized clocksource") in v2.6.26+ [2]: QEMU commit f0ccf77078 ("hpet: fix and cleanup persistence of interrupt status") [3]: https://lore.kernel.org/qemu-devel/8183674f-a9cc-4727-bb52-fe3d3e44804b@proxmox.com/ [4]: https://forum.proxmox.com/threads/161849/post-756793 [5]: https://lore.kernel.org/qemu-devel/CABgObfaKJ5NFVKmYLFmu4C0iZZLJJtcWksLCzyA0tBoz0koZ4A@mail.gmail.com/ [6]: https://lore.kernel.org/qemu-devel/CABgObfYnOzg=BPeG5BjSmGEV_Q0pR7xGg6L3XNQCONtU_GiuGA@mail.gmail.com/ Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-6-f.ebner@proxmox.com --- src/PVE/QemuServer.pm | 2 +- src/PVE/QemuServer/Cfg2Cmd.pm | 30 ++++++++++++++++++++++++++--- src/PVE/QemuServer/Cfg2Cmd/Timer.pm | 2 ++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index f1025cfa..45daa06c 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -3382,7 +3382,7 @@ sub config_to_command { } # For now, handles only specific parts, but the final goal is to cover everything. - my $cfg2cmd = PVE::QemuServer::Cfg2Cmd->new($conf, $defaults); + my $cfg2cmd = PVE::QemuServer::Cfg2Cmd->new($conf, $defaults, $version_guard); my $generated = $cfg2cmd->generate(); push $cmd->@*, '-global', $_ for ($generated->global_flags() // [])->@*; push $machineFlags->@*, ($generated->machine_flags() // [])->@*; diff --git a/src/PVE/QemuServer/Cfg2Cmd.pm b/src/PVE/QemuServer/Cfg2Cmd.pm index 6b26ab23..c7ee0165 100644 --- a/src/PVE/QemuServer/Cfg2Cmd.pm +++ b/src/PVE/QemuServer/Cfg2Cmd.pm @@ -7,15 +7,16 @@ use PVE::QemuServer::Cfg2Cmd::Timer; use PVE::QemuServer::Helpers; sub new { - my ($class, $conf, $defaults) = @_; + my ($class, $conf, $defaults, $version_guard) = @_; my $self = bless { conf => $conf, defaults => $defaults, + 'version-guard' => $version_guard, }, $class; - my $ostype = $self->get_prop('ostype'); - $self->{'windows-version'} = PVE::QemuServer::Helpers::windows_version($ostype); + $self->{ostype} = $self->get_prop('ostype'); + $self->{'windows-version'} = PVE::QemuServer::Helpers::windows_version($self->{ostype}); return $self; } @@ -74,12 +75,35 @@ sub rtc_flags { return $self->{'rtc-flags'}; } +=head3 is_linux + + if ($self->is_linux()) { + do_something_for_linux_vms(); + } + +Check if the virtual machine is configured for running Linux. Does not include the C os type +by default. Specify C<$include_l24> if that is desired. + +=cut + +sub is_linux { + my ($self, $include_l24) = @_; + + return $self->{ostype} eq 'l26' || ($include_l24 && $self->{ostype} eq 'l24'); +} + sub windows_version { my ($self) = @_; return $self->{'windows-version'}; } +sub version_guard { + my ($self, $major, $minor, $pve) = @_; + + $self->{'version-guard'}->($major, $minor, $pve); +} + sub generate { my ($self) = @_; diff --git a/src/PVE/QemuServer/Cfg2Cmd/Timer.pm b/src/PVE/QemuServer/Cfg2Cmd/Timer.pm index d4b16af0..452c15b2 100644 --- a/src/PVE/QemuServer/Cfg2Cmd/Timer.pm +++ b/src/PVE/QemuServer/Cfg2Cmd/Timer.pm @@ -21,6 +21,8 @@ sub generate { if ($cfg2cmd->windows_version() >= 6) { $cfg2cmd->add_global_flag('kvm-pit.lost_tick_policy=discard'); $cfg2cmd->add_machine_flag('hpet=off'); + } elsif ($cfg2cmd->is_linux() && $cfg2cmd->version_guard(10, 1, 0)) { + $cfg2cmd->add_machine_flag('hpet=off'); } $cfg2cmd->add_rtc_flag('driftfix=slew') if $time_drift_fix; From 86e52f86603dc57a109af57aa4a8b29bed55b1a7 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 29 Sep 2025 14:56:51 +0200 Subject: [PATCH 73/79] tests: cfg2cmd: regenerate with QEMU 10.1 binary For the rationale about the change see "cfg2cmd: turn off hpet for Linux VMs running at least kernel 2.6 and machine type >= 10.1". Bump the build dependency in d/control. Signed-off-by: Fiona Ebner Link: https://lore.proxmox.com/20250929125852.102343-7-f.ebner@proxmox.com --- debian/control | 2 +- src/test/cfg2cmd/bootorder-empty.conf.cmd | 2 +- src/test/cfg2cmd/bootorder-legacy.conf.cmd | 2 +- src/test/cfg2cmd/bootorder.conf.cmd | 2 +- src/test/cfg2cmd/cputype-icelake-client-deprecation.conf.cmd | 2 +- src/test/cfg2cmd/custom-cpu-model-defaults.conf.cmd | 2 +- src/test/cfg2cmd/efidisk-on-rbd.conf.cmd | 2 +- src/test/cfg2cmd/ide.conf.cmd | 2 +- src/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd | 2 +- src/test/cfg2cmd/memory-hotplug.conf.cmd | 2 +- src/test/cfg2cmd/memory-hugepages-1g.conf.cmd | 2 +- src/test/cfg2cmd/memory-hugepages-2m.conf.cmd | 2 +- src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd | 2 +- src/test/cfg2cmd/netdev-7.1.conf.cmd | 2 +- src/test/cfg2cmd/netdev_vxlan.conf.cmd | 2 +- src/test/cfg2cmd/q35-ide.conf.cmd | 2 +- src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd | 2 +- src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd | 2 +- src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd | 2 +- src/test/cfg2cmd/q35-linux-hostpci.conf.cmd | 2 +- src/test/cfg2cmd/q35-simple.conf.cmd | 2 +- src/test/cfg2cmd/seabios_serial.conf.cmd | 2 +- src/test/cfg2cmd/simple-btrfs.conf.cmd | 2 +- src/test/cfg2cmd/simple-cifs.conf.cmd | 2 +- src/test/cfg2cmd/simple-disk-passthrough.conf.cmd | 2 +- src/test/cfg2cmd/simple-rbd.conf.cmd | 2 +- src/test/cfg2cmd/simple-virtio-blk.conf.cmd | 2 +- src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd | 2 +- src/test/cfg2cmd/simple1.conf.cmd | 2 +- src/test/cfg2cmd/startdate-l26.conf.cmd | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/debian/control b/debian/control index f02ef742..5ac6b0fc 100644 --- a/debian/control +++ b/debian/control @@ -25,7 +25,7 @@ Build-Depends: debhelper-compat (= 13), pve-edk2-firmware-ovmf (>= 4.2025.02-3), pve-firewall, pve-ha-manager , - pve-qemu-kvm (>= 9.2~), + pve-qemu-kvm (>= 10.1~), Standards-Version: 4.5.1 Homepage: https://www.proxmox.com diff --git a/src/test/cfg2cmd/bootorder-empty.conf.cmd b/src/test/cfg2cmd/bootorder-empty.conf.cmd index af4a5ba6..32b72a27 100644 --- a/src/test/cfg2cmd/bootorder-empty.conf.cmd +++ b/src/test/cfg2cmd/bootorder-empty.conf.cmd @@ -40,4 +40,4 @@ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/bootorder-legacy.conf.cmd b/src/test/cfg2cmd/bootorder-legacy.conf.cmd index 6b848a9b..9e558167 100644 --- a/src/test/cfg2cmd/bootorder-legacy.conf.cmd +++ b/src/test/cfg2cmd/bootorder-legacy.conf.cmd @@ -40,4 +40,4 @@ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,bootindex=302,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=100,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/bootorder.conf.cmd b/src/test/cfg2cmd/bootorder.conf.cmd index a3c6bd39..430926c0 100644 --- a/src/test/cfg2cmd/bootorder.conf.cmd +++ b/src/test/cfg2cmd/bootorder.conf.cmd @@ -40,4 +40,4 @@ -device 'virtio-blk-pci,drive=drive-virtio1,id=virtio1,bus=pci.0,addr=0xb,iothread=iothread-virtio1,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=101,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/cputype-icelake-client-deprecation.conf.cmd b/src/test/cfg2cmd/cputype-icelake-client-deprecation.conf.cmd index e6429c9f..42e97987 100644 --- a/src/test/cfg2cmd/cputype-icelake-client-deprecation.conf.cmd +++ b/src/test/cfg2cmd/cputype-icelake-client-deprecation.conf.cmd @@ -30,4 +30,4 @@ -device 'virtio-scsi-pci,id=scsihw0,bus=pci.0,addr=0x5' \ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"qcow2","file":{"aio":"io_uring","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/var/lib/vz/images/8006/base-8006-disk-0.qcow2","node-name":"e417d5947e69c5890b1e3ddf8a68167","read-only":false},"node-name":"f417d5947e69c5890b1e3ddf8a68167","read-only":false},"node-name":"drive-scsi0","read-only":false,"throttle-group":"throttle-drive-scsi0"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/custom-cpu-model-defaults.conf.cmd b/src/test/cfg2cmd/custom-cpu-model-defaults.conf.cmd index 2908fdc0..57f6bb34 100644 --- a/src/test/cfg2cmd/custom-cpu-model-defaults.conf.cmd +++ b/src/test/cfg2cmd/custom-cpu-model-defaults.conf.cmd @@ -24,4 +24,4 @@ -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd b/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd index dda9d91b..fc6d68a4 100644 --- a/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd +++ b/src/test/cfg2cmd/efidisk-on-rbd.conf.cmd @@ -32,4 +32,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=pc+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/ide.conf.cmd b/src/test/cfg2cmd/ide.conf.cmd index 23282a18..2503e9a4 100644 --- a/src/test/cfg2cmd/ide.conf.cmd +++ b/src/test/cfg2cmd/ide.conf.cmd @@ -43,4 +43,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd b/src/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd index e069bd6b..0f071ac0 100644 --- a/src/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd +++ b/src/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd @@ -61,4 +61,4 @@ -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/memory-hotplug.conf.cmd b/src/test/cfg2cmd/memory-hotplug.conf.cmd index af80917b..5402b5ee 100644 --- a/src/test/cfg2cmd/memory-hotplug.conf.cmd +++ b/src/test/cfg2cmd/memory-hotplug.conf.cmd @@ -173,4 +173,4 @@ -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/memory-hugepages-1g.conf.cmd b/src/test/cfg2cmd/memory-hugepages-1g.conf.cmd index 73c3036f..e62aa768 100644 --- a/src/test/cfg2cmd/memory-hugepages-1g.conf.cmd +++ b/src/test/cfg2cmd/memory-hugepages-1g.conf.cmd @@ -29,4 +29,4 @@ -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/memory-hugepages-2m.conf.cmd b/src/test/cfg2cmd/memory-hugepages-2m.conf.cmd index 9eb85a72..89e43393 100644 --- a/src/test/cfg2cmd/memory-hugepages-2m.conf.cmd +++ b/src/test/cfg2cmd/memory-hugepages-2m.conf.cmd @@ -29,4 +29,4 @@ -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd b/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd index 43e40742..fe2af829 100644 --- a/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd +++ b/src/test/cfg2cmd/netdev-7.1-multiqueues.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on,queues=2' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,vectors=6,mq=on,packed=on,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=900' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/netdev-7.1.conf.cmd b/src/test/cfg2cmd/netdev-7.1.conf.cmd index 10404de4..7b858d92 100644 --- a/src/test/cfg2cmd/netdev-7.1.conf.cmd +++ b/src/test/cfg2cmd/netdev-7.1.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=900' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/netdev_vxlan.conf.cmd b/src/test/cfg2cmd/netdev_vxlan.conf.cmd index 7de574a7..3d6c8da7 100644 --- a/src/test/cfg2cmd/netdev_vxlan.conf.cmd +++ b/src/test/cfg2cmd/netdev_vxlan.conf.cmd @@ -25,4 +25,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1450' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/q35-ide.conf.cmd b/src/test/cfg2cmd/q35-ide.conf.cmd index 9af48002..36f5264e 100644 --- a/src/test/cfg2cmd/q35-ide.conf.cmd +++ b/src/test/cfg2cmd/q35-ide.conf.cmd @@ -42,4 +42,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=q35+pve1' + -machine 'hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd index 7413a651..b5d8997e 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-mapping.conf.cmd @@ -36,4 +36,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd index f8435778..9cfc71a7 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-multifunction.conf.cmd @@ -36,4 +36,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd index b314b8ad..7b3f65f4 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci-x-pci-overrides.conf.cmd @@ -35,4 +35,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd b/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd index b6914255..7226d478 100644 --- a/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd +++ b/src/test/cfg2cmd/q35-linux-hostpci.conf.cmd @@ -41,4 +41,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/q35-simple.conf.cmd b/src/test/cfg2cmd/q35-simple.conf.cmd index 9cdb5bdb..307aeb4a 100644 --- a/src/test/cfg2cmd/q35-simple.conf.cmd +++ b/src/test/cfg2cmd/q35-simple.conf.cmd @@ -29,4 +29,4 @@ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=2E:01:68:F9:9C:87,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'pflash0=pflash0,pflash1=drive-efidisk0,type=q35+pve1' + -machine 'pflash0=pflash0,pflash1=drive-efidisk0,hpet=off,type=q35+pve0' diff --git a/src/test/cfg2cmd/seabios_serial.conf.cmd b/src/test/cfg2cmd/seabios_serial.conf.cmd index ce2d7cf2..e8c66c7b 100644 --- a/src/test/cfg2cmd/seabios_serial.conf.cmd +++ b/src/test/cfg2cmd/seabios_serial.conf.cmd @@ -32,4 +32,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'smm=off,type=pc+pve1' + -machine 'hpet=off,smm=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-btrfs.conf.cmd b/src/test/cfg2cmd/simple-btrfs.conf.cmd index b73aae79..812ef7e8 100644 --- a/src/test/cfg2cmd/simple-btrfs.conf.cmd +++ b/src/test/cfg2cmd/simple-btrfs.conf.cmd @@ -41,4 +41,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=3,drive=drive-scsi3,id=scsi3,device_id=drive-scsi3,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-cifs.conf.cmd b/src/test/cfg2cmd/simple-cifs.conf.cmd index 4174d061..9819d545 100644 --- a/src/test/cfg2cmd/simple-cifs.conf.cmd +++ b/src/test/cfg2cmd/simple-cifs.conf.cmd @@ -37,4 +37,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=2,drive=drive-scsi2,id=scsi2,device_id=drive-scsi2,write-cache=off' \ -blockdev '{"detect-zeroes":"unmap","discard":"unmap","driver":"throttle","file":{"cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"raw","file":{"aio":"native","cache":{"direct":true,"no-flush":false},"detect-zeroes":"unmap","discard":"unmap","driver":"file","filename":"/mnt/pve/cifs-store/images/8006/vm-8006-disk-0.raw","node-name":"e7042ee58e764b1296ad54014cb9a03","read-only":false},"node-name":"f7042ee58e764b1296ad54014cb9a03","read-only":false},"node-name":"drive-scsi3","read-only":false,"throttle-group":"throttle-drive-scsi3"}' \ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=3,drive=drive-scsi3,id=scsi3,device_id=drive-scsi3,write-cache=off' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd b/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd index 2b3a22e5..218db679 100644 --- a/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd +++ b/src/test/cfg2cmd/simple-disk-passthrough.conf.cmd @@ -37,4 +37,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi1,id=scsi1,device_id=drive-scsi1,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-rbd.conf.cmd b/src/test/cfg2cmd/simple-rbd.conf.cmd index 29dfaacc..6730fcd0 100644 --- a/src/test/cfg2cmd/simple-rbd.conf.cmd +++ b/src/test/cfg2cmd/simple-rbd.conf.cmd @@ -53,4 +53,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=7,drive=drive-scsi7,id=scsi7,device_id=drive-scsi7,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-virtio-blk.conf.cmd b/src/test/cfg2cmd/simple-virtio-blk.conf.cmd index efec4a20..de193c5b 100644 --- a/src/test/cfg2cmd/simple-virtio-blk.conf.cmd +++ b/src/test/cfg2cmd/simple-virtio-blk.conf.cmd @@ -32,4 +32,4 @@ -device 'virtio-blk-pci,drive=drive-virtio0,id=virtio0,bus=pci.0,addr=0xa,iothread=iothread-virtio0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd b/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd index 21bfd638..302308b5 100644 --- a/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd +++ b/src/test/cfg2cmd/simple-zfs-over-iscsi.conf.cmd @@ -41,4 +41,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=3,drive=drive-scsi3,id=scsi3,device_id=drive-scsi3,write-cache=off' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/simple1.conf.cmd b/src/test/cfg2cmd/simple1.conf.cmd index eef2868b..e0954235 100644 --- a/src/test/cfg2cmd/simple1.conf.cmd +++ b/src/test/cfg2cmd/simple1.conf.cmd @@ -32,4 +32,4 @@ -device 'scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,device_id=drive-scsi0,bootindex=100,write-cache=on' \ -netdev 'type=tap,id=net0,ifname=tap8006i0,script=/usr/libexec/qemu-server/pve-bridge,downscript=/usr/libexec/qemu-server/pve-bridgedown,vhost=on' \ -device 'virtio-net-pci,mac=A2:C0:43:77:08:A0,netdev=net0,bus=pci.0,addr=0x12,id=net0,rx_queue_size=1024,tx_queue_size=256,bootindex=300,host_mtu=1500' \ - -machine 'type=pc+pve1' + -machine 'hpet=off,type=pc+pve0' diff --git a/src/test/cfg2cmd/startdate-l26.conf.cmd b/src/test/cfg2cmd/startdate-l26.conf.cmd index 9a3ba21e..2d3f56e3 100644 --- a/src/test/cfg2cmd/startdate-l26.conf.cmd +++ b/src/test/cfg2cmd/startdate-l26.conf.cmd @@ -24,4 +24,4 @@ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ -rtc 'base=2006-06-17T16:01:21' \ - -machine 'type=pc+pve0' + -machine 'hpet=off,type=pc+pve0' From 78e5d8a8d06a061c464dfd5e3d794f4d729d02b1 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Fri, 3 Oct 2025 22:12:27 +0200 Subject: [PATCH 74/79] bump version to 9.0.23 Signed-off-by: Thomas Lamprecht --- debian/changelog | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/debian/changelog b/debian/changelog index 2c1a8eed..5cb73077 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,38 @@ +qemu-server (9.0.23) trixie; urgency=medium + + * fix #6713: snapshot volume chain: fix snapshot after disk move with + zeroinit. + + * api: dbus-vmstate: fix return property name in schema. + + * vm status: also queue query-proxmox-support QMP commands to avoid stacking + timeouts. + + * api: add missing snapshot info to get-config return schema. + + * agent: implement fsfreeze helper to better handle lost commands to avoid + unnecessarily blocking the QMP socket for a prolonged time. + + * migration: conntrack: work around systemd issue where scope for VM might + become blocked. + + * fix #6828: remote migration: bump timeout for writing configuration to + accommodate volume activation. Allow for up to 2 minutes instead of just + 10 seconds. + + * fix #6882: backup provider api: fix backup with TPM state by correctly + generating node name. + + * backup: fleecing: avoid warning when querying block node size for TPM + state. + + * cfg2cmd: turn off the high-precision event timer (HPET) for Linux VMs + running at least kernel 2.6 and machine type >= 10.1, which will avoid + slightly increased CPU usage with newer QEMU versions. Further, Linux + kernel since v2.6.26+ (from July 2008!) can use the kvm-clock timer. + + -- Proxmox Support Team Fri, 03 Oct 2025 22:12:22 +0200 + qemu-server (9.0.22) trixie; urgency=medium * partially fix #6805: From 14823177f52aa46533d697ac2d6171a9113ed954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=B6ppl?= Date: Mon, 6 Oct 2025 17:52:29 +0200 Subject: [PATCH 75/79] api: create/store: allow adding VM as HA resource after creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the creation and restore actions with a 'ha-managed' parameter that, if enabled, will also add the VM as a new HA resource. The 'state' parameter for this new resource will match the value of the 'start' parameter used during creation of the VM, such that the resulting state of the resource and VM both match the user's expectation (avoid situation where user creates a VM, does not select 'Start after creation', but the default 'started' state of the resource would start the VM anyway). Signed-off-by: Michael Köppl Link: https://lore.proxmox.com/20251006155233.267374-2-m.koeppl@proxmox.com --- src/PVE/API2/Qemu.pm | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm index 7fced6c6..71bedc1e 100644 --- a/src/PVE/API2/Qemu.pm +++ b/src/PVE/API2/Qemu.pm @@ -1170,6 +1170,12 @@ __PACKAGE__->register_method({ default => 0, description => "Start VM after it was created successfully.", }, + 'ha-managed' => { + optional => 1, + type => 'boolean', + default => 0, + description => "Add the VM as a HA resource after it was created.", + }, 'import-working-storage' => get_standard_option( 'pve-storage-id', { @@ -1204,6 +1210,7 @@ __PACKAGE__->register_method({ my $force = extract_param($param, 'force'); my $pool = extract_param($param, 'pool'); my $start_after_create = extract_param($param, 'start'); + my $ha_managed = extract_param($param, 'ha-managed'); my $storage = extract_param($param, 'storage'); my $unique = extract_param($param, 'unique'); my $live_restore = extract_param($param, 'live-restore'); @@ -1380,6 +1387,15 @@ __PACKAGE__->register_method({ eval { PVE::API2::Qemu->vm_start({ vmid => $vmid, node => $node }) }; warn $@ if $@; } + + if ($ha_managed) { + print "Add as HA resource\n"; + my $state = $start_after_create ? 'started' : 'stopped'; + eval { + PVE::API2::HA::Resources->create({ sid => "vm:$vmid", state => $state }); + }; + warn $@ if $@; + } }; my $createfn = sub { @@ -1463,6 +1479,15 @@ __PACKAGE__->register_method({ PVE::QemuConfig->lock_config_full($vmid, 1, $realcmd); + if ($ha_managed) { + print "Add as HA resource\n"; + my $state = $start_after_create ? 'started' : 'stopped'; + eval { + PVE::API2::HA::Resources->create({ sid => "vm:$vmid", state => $state }); + }; + warn $@ if $@; + } + if ($start_after_create && !$live_restore) { print "Execute autostart\n"; eval { PVE::API2::Qemu->vm_start({ vmid => $vmid, node => $node }) }; From 7f7776c18e8be5d2e227ba7099027e57d4de21ed Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Fri, 10 Oct 2025 18:02:20 +0100 Subject: [PATCH 76/79] qmeventd: add block write threshold event handling --- src/qmeventd/qmeventd.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/qmeventd/qmeventd.c b/src/qmeventd/qmeventd.c index 1d9eb74a..7bae13f9 100644 --- a/src/qmeventd/qmeventd.c +++ b/src/qmeventd/qmeventd.c @@ -43,7 +43,7 @@ #define DEFAULT_KILL_TIMEOUT 60 -static int verbose = 0; +static int verbose = 1; static int kill_timeout = DEFAULT_KILL_TIMEOUT; static int epoll_fd = 0; static const char *progname; @@ -209,6 +209,25 @@ void handle_qmp_event(struct Client *client, struct json_object *obj) { // check if a backup is running and kill QEMU process if not terminate_check(client); + } else if (!strcmp(json_object_get_string(event), "BLOCK_WRITE_THRESHOLD")) { + struct json_object *data; + struct json_object *nodename; + if (json_object_object_get_ex(obj, "data", &data) && + json_object_object_get_ex(data, "node-name", &nodename)) { + + // needs concurrency control + char extend_queue_path[] = "/etc/pve/extend-queue"; + FILE *p_extend_queue = fopen(extend_queue_path, "a"); + if (p_extend_queue == NULL) { + VERBOSE_PRINT( + "%s: Couldn't open extend queue file %s", client->qemu.vmid, extend_queue_path + ); + } else { + const char *nodename_string = json_object_get_string(nodename); + fprintf(p_extend_queue, "%s: %s\n", client->qemu.vmid, nodename_string); + } + fclose(p_extend_queue); + } } } From a61beb133f6f269f12cbbd50305ef72a66a53c07 Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Sat, 2 Aug 2025 16:58:53 +0100 Subject: [PATCH 77/79] blockdev: add set write threshold --- src/PVE/QemuServer.pm | 22 ++++++++++++++++ src/PVE/QemuServer/Blockdev.pm | 47 ++++++++++++++++++++++++++++++++++ src/PVE/QemuServer/Drive.pm | 7 +++++ 3 files changed, 76 insertions(+) diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 45daa06c..de1c39a5 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5729,6 +5729,28 @@ sub vm_start_nolock { warn $@ if $@; } + # set write threshold for LVM thin provisioning disks + PVE::QemuConfig->foreach_volume( + $conf, + sub { + my ($ds, $drive) = @_; + return if PVE::QemuServer::drive_is_cdrom($drive, 1); + my $volid = $drive->{file}; + if ( $volid ne 'none') { + my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); + my $snapshots = PVE::Storage::volume_snapshot_info($storecfg, $volid); + my $parentid = $snapshots->{'current'}->{parent}; + # for now only set write_threshold for volumes that have snapshots + # FIX: Change to only thin drives + if ($parentid) { + PVE::QemuServer::Blockdev::set_write_threshold( + $storecfg, $vmid, $drive_id, $volid + ); + } + } + }, + ); + #start nbd server for storage migration if (my $nbd = $migrate_opts->{nbd}) { diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 8fa5eb51..9f8b635c 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -830,6 +830,49 @@ sub set_io_throttle { } } +sub block_set_write_threshold { + my ($vmid, $nodename, $threshold) = @_; + + print "set threshold $nodename $threshold\n"; + + PVE::QemuServer::mon_cmd( + $vmid, + "block-set-write-threshold", + 'node-name' => $nodename, + 'write-threshold' => int($threshold), + ); +} + +sub compute_write_threshold { + my ($storecfg, $scfg, $volid) = @_; + + my $lv_size = PVE::Storage::volume_size_info($storecfg, $volid, 5); + + my $write_threshold = $lv_size - $scfg->{chunksize} * (1 - $scfg->{'chunk-percentage'}); + + return $write_threshold; +} + +sub set_write_threshold { + my ($storecfg, $vmid, $drive_id, $volid, $options) = @_; + + my ($storeid) = PVE::Storage::parse_volume_id($volid); + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); + my $support_qemu_snapshots = PVE::Storage::volume_qemu_snapshot_method($storecfg, $volid); + + # set write threshold is only supported for lvm storage using + # qcow2+external snapshots + return if $scfg->{type} ne 'lvm' || $support_qemu_snapshots ne 'mixed'; + # return if drive is not set as thin + # return if !$drive->{thin}; + + my $nodename = get_node_name('file', $drive_id, $volid, $options); + my $write_threshold = compute_write_threshold($storecfg, $scfg, $volid); + + print "setting threshold for $volid from $storeid\n"; + block_set_write_threshold($vmid, $nodename, $write_threshold); +} + sub blockdev_external_snapshot { my ($storecfg, $vmid, $machine_version, $deviceid, $drive, $snap, $parent_snap) = @_; @@ -878,6 +921,10 @@ sub blockdev_external_snapshot { node => $snap_fmt_blockdev->{'node-name'}, overlay => $new_fmt_blockdev->{'node-name'}, ); + + # FIX: only if thin + my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive); + set_write_threshold($storecfg, $vmid, $drive_id, $volid); } sub blockdev_delete { diff --git a/src/PVE/QemuServer/Drive.pm b/src/PVE/QemuServer/Drive.pm index 79dd22e6..44f477a9 100644 --- a/src/PVE/QemuServer/Drive.pm +++ b/src/PVE/QemuServer/Drive.pm @@ -253,6 +253,13 @@ my %drivedesc_base = ( optional => 1, default => 0, }, + thin => { + type => 'boolean', + description => + 'Controls whether a drive should be thin provisioned', + optional => 1, + default => 0, + }, ); my %iothread_fmt = ( From 21e3e5a09843ea6ccccd30edb2c7f5fa0df63153 Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Sat, 13 Sep 2025 18:54:06 +0100 Subject: [PATCH 78/79] blockdev: add query-blockstats qmp command --- src/PVE/QemuServer/Blockdev.pm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 9f8b635c..0e29accc 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -113,6 +113,21 @@ sub get_block_info { return $block_info; } +sub get_block_stats { + my ($vmid) = @_; + + my $block_stats = {}; + + my $qmp_block_stats = mon_cmd($vmid, "query-blockstats"); + for my $info ($qmp_block_stats->@*) { + my $qdev_id = $info->{qdev} or next; + my $drive_id = qdev_id_to_drive_id($qdev_id); + $block_stats->{$drive_id} = $info; + } + + return $block_stats; +} + my sub get_node_name { my ($type, $drive_id, $volid, $options) = @_; From 9405e35f8bd22ed71f788865664a70c892a6cc9c Mon Sep 17 00:00:00 2001 From: Tiago Sousa Date: Fri, 10 Oct 2025 18:11:29 +0100 Subject: [PATCH 79/79] blockdev: add underlay resize --- src/PVE/QemuServer/Blockdev.pm | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/PVE/QemuServer/Blockdev.pm b/src/PVE/QemuServer/Blockdev.pm index 0e29accc..5083fad5 100644 --- a/src/PVE/QemuServer/Blockdev.pm +++ b/src/PVE/QemuServer/Blockdev.pm @@ -725,6 +725,24 @@ sub resize { ); } +sub underlay_resize { + my ($storecfg, $vmid, $drive_id, $volid) = @_; + + my $running = PVE::QemuServer::Helpers::vm_running_locally($vmid); + + # get backing_snap + my $snapshots = PVE::Storage::volume_snapshot_info($storecfg, $volid); + my $backing_snap = $snapshots->{current}->{parent}; + my $size = PVE::Storage::volume_underlay_resize($storecfg, $volid, $backing_snap); + + return if !$running; + my $block_info = get_block_info($vmid); + my $inserted = $block_info->{$drive_id}->{inserted} + or die "no block node inserted for drive '$drive_id'\n"; + + set_write_threshold($storecfg, $vmid, $drive_id, $volid); +} + my sub blockdev_change_medium { my ($storecfg, $vmid, $qdev_id, $drive) = @_; @@ -861,7 +879,7 @@ sub block_set_write_threshold { sub compute_write_threshold { my ($storecfg, $scfg, $volid) = @_; - my $lv_size = PVE::Storage::volume_size_info($storecfg, $volid, 5); + my $lv_size = PVE::Storage::volume_underlay_size_info($storecfg, $volid, 5); my $write_threshold = $lv_size - $scfg->{chunksize} * (1 - $scfg->{'chunk-percentage'});