From ea1c21108f774c3440704780bda335535f9a95a4 Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Tue, 7 Apr 2020 15:56:16 +0200 Subject: [PATCH] Include "-cpu" parameter with snapshots/suspend 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 --- PVE/API2/Qemu.pm | 1 + PVE/QemuConfig.pm | 26 +++++++++++++++++++------- PVE/QemuServer.pm | 31 ++++++++++++++++++++++--------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 10e49661..b2209342 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -1129,6 +1129,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 f32618ef..d29b88b5 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -5,6 +5,7 @@ use warnings; use PVE::AbstractConfig; use PVE::INotify; +use PVE::QemuServer::CPUConfig; use PVE::QemuServer::Drive; use PVE::QemuServer::Helpers; use PVE::QemuServer::Monitor qw(mon_cmd); @@ -186,15 +187,20 @@ 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 to ensure consistency of custom CPU models + my $runningcpu; + if (my $pid = PVE::QemuServer::check_running($vmid)) { + $runningcpu = PVE::QemuServer::CPUConfig::get_cpu_from_running_vm($pid); } + if (!$suspend) { + $conf = $conf->{snapshots}->{$snapname}; + } + + $conf->{vmstate} = $statefile; + $conf->{runningmachine} = $runningmachine; + $conf->{runningcpu} = $runningcpu; + return $statefile; } @@ -340,6 +346,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). @@ -395,6 +406,7 @@ sub __snapshot_rollback_vm_start { my $params = { statefile => $vmstate, forcemachine => $data->{forcemachine}, + forcecpu => $data->{forcecpu}, }; PVE::QemuServer::vm_start($storecfg, $vmid, $params); } diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 85034434..12f76b87 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -589,8 +589,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.", @@ -1970,7 +1977,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}; } @@ -4884,14 +4892,16 @@ sub vm_start_nolock { PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1); my $forcemachine = $params->{forcemachine}; + my $forcecpu = $params->{forcecpu}; if ($resume) { - # enforce machine type on suspended vm to ensure HW compatibility + # enforce machine and CPU type on suspended vm to ensure HW compatibility $forcemachine = $conf->{runningmachine}; + $forcecpu = $conf->{runningcpu}; print "Resuming suspended VM\n"; } my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, - $defaults, $forcemachine, $params->{forcecpu}); + $defaults, $forcemachine, $forcecpu); my $migration_ip; my $get_migration_ip = sub { @@ -5155,7 +5165,7 @@ sub vm_start_nolock { 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); } @@ -5169,13 +5179,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 @@ -5184,7 +5196,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); } @@ -5458,7 +5471,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 $@;