Just like with live-migration, custom CPU models might change after a snapshot has been taken (or a VM suspended), which would lead to a different QEMU invocation on rollback/resume.
Save the "-cpu" argument as a new "runningcpu" option into the VM conf akin to "runningmachine" and use as override during rollback/resume. No functional change with non-custom CPU types intended. Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- New in v7. PVE/API2/Qemu.pm | 1 + PVE/QemuConfig.pm | 36 +++++++++++++++++++++++++++--------- PVE/QemuServer.pm | 28 ++++++++++++++++++++-------- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 5ea6cf2..e96a0c0 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -1099,6 +1099,7 @@ my $update_vm_api = sub { push @delete, 'lock'; # this is the real deal to write it out } push @delete, 'runningmachine' if $conf->{runningmachine}; + push @delete, 'runningcpu' if $conf->{runningcpu}; } PVE::QemuConfig->check_lock($conf) if !$skiplock; diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm index 1ba728a..852c309 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -5,9 +5,10 @@ use warnings; use PVE::AbstractConfig; use PVE::INotify; +use PVE::QemuServer; +use PVE::QemuServer::CPUConfig; use PVE::QemuServer::Helpers; use PVE::QemuServer::Monitor qw(mon_cmd); -use PVE::QemuServer; use PVE::QemuServer::Machine; use PVE::Storage; use PVE::Tools; @@ -156,15 +157,26 @@ sub __snapshot_save_vmstate { my $statefile = PVE::Storage::vdisk_alloc($storecfg, $target, $vmid, 'raw', $name, $size*1024); my $runningmachine = PVE::QemuServer::Machine::get_current_qemu_machine($vmid); - if ($suspend) { - $conf->{vmstate} = $statefile; - $conf->{runningmachine} = $runningmachine; - } else { - my $snap = $conf->{snapshots}->{$snapname}; - $snap->{vmstate} = $statefile; - $snap->{runningmachine} = $runningmachine; + # get current QEMU -cpu argument + my $runningcpu; + if (my $pid = PVE::QemuServer::check_running($vmid)) { + my $cmdline = PVE::QemuServer::Helpers::parse_cmdline($pid); + die "could not read commandline of running machine\n" + if !$cmdline->{cpu}->{value}; + + # sanitize and untaint value + $cmdline->{cpu}->{value} =~ $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re; + $runningcpu = $1; } + if (!$suspend) { + $conf = $conf->{snapshots}->{$snapname}; + } + + $conf->{vmstate} = $statefile; + $conf->{runningmachine} = $runningmachine; + $conf->{runningcpu} = $runningcpu; + return $statefile; } @@ -310,6 +322,11 @@ sub __snapshot_rollback_hook { if (defined($conf->{runningmachine})) { $data->{forcemachine} = $conf->{runningmachine}; delete $conf->{runningmachine}; + + # runningcpu is newer than runningmachine, so assume it only exists + # here, if at all + $data->{forcecpu} = delete $conf->{runningcpu} + if defined($conf->{runningcpu}); } else { # Note: old code did not store 'machine', so we try to be smart # and guess the snapshot was generated with kvm 1.4 (pc-i440fx-1.4). @@ -362,7 +379,8 @@ sub __snapshot_rollback_vm_start { my ($class, $vmid, $vmstate, $data) = @_; my $storecfg = PVE::Storage::config(); - PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, undef, $data->{forcemachine}); + PVE::QemuServer::vm_start($storecfg, $vmid, $vmstate, undef, undef, undef, + $data->{forcemachine}, undef, undef, undef, undef, undef, $data->{forcecpu}); } sub __snapshot_rollback_get_unused { diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 4252b68..ab890cb 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -532,8 +532,15 @@ EODESCR optional => 1, }), runningmachine => get_standard_option('pve-qemu-machine', { - description => "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.", + description => "Specifies the QEMU machine type of the running vm. This is used internally for snapshots.", }), + runningcpu => { + description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used internally for snapshots.", + optional => 1, + type => 'string', + pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re, + format_description => 'QEMU -cpu parameter' + }, machine => get_standard_option('pve-qemu-machine'), arch => { description => "Virtual processor architecture. Defaults to the host.", @@ -2364,7 +2371,8 @@ sub json_config_properties { my $prop = shift; foreach my $opt (keys %$confdesc) { - next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine'; + next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || + $opt eq 'runningmachine' || $opt eq 'runningcpu'; $prop->{$opt} = $confdesc->{$opt}; } @@ -5280,8 +5288,9 @@ sub vm_start { PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1); if ($is_suspended) { - # enforce machine type on suspended vm to ensure HW compatibility + # enforce machine type and CPU on suspended vm to ensure HW compatibility $forcemachine = $conf->{runningmachine}; + $force_cpu = $conf->{runningcpu}; print "Resuming suspended VM\n"; } @@ -5527,7 +5536,7 @@ sub vm_start { PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); PVE::Storage::vdisk_free($storecfg, $vmstate); } - delete $conf->@{qw(lock vmstate runningmachine)}; + delete $conf->@{qw(lock vmstate runningmachine runningcpu)}; PVE::QemuConfig->write_config($vmid, $conf); } @@ -5540,13 +5549,15 @@ sub vm_commandline { my $conf = PVE::QemuConfig->load_config($vmid); my $forcemachine; + my $forcecpu; if ($snapname) { my $snapshot = $conf->{snapshots}->{$snapname}; die "snapshot '$snapname' does not exist\n" if !defined($snapshot); - # check for a 'runningmachine' in snapshot - $forcemachine = $snapshot->{runningmachine} if $snapshot->{runningmachine}; + # check for machine or CPU overrides in snapshot + $forcemachine = $snapshot->{runningmachine}; + $forcecpu = $snapshot->{runningcpu}; $snapshot->{digest} = $conf->{digest}; # keep file digest for API @@ -5555,7 +5566,8 @@ sub vm_commandline { my $defaults = load_defaults(); - my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine); + my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, + $forcemachine, $forcecpu); return PVE::Tools::cmd2string($cmd); } @@ -5829,7 +5841,7 @@ sub vm_suspend { mon_cmd($vmid, "savevm-end"); PVE::Storage::deactivate_volumes($storecfg, [$vmstate]); PVE::Storage::vdisk_free($storecfg, $vmstate); - delete $conf->@{qw(vmstate runningmachine)}; + delete $conf->@{qw(vmstate runningmachine runningcpu)}; PVE::QemuConfig->write_config($vmid, $conf); }; warn $@ if $@; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel