[pve-devel] [PATCH v7 qemu-server 10/10] Include "-cpu" parameter with snapshots/suspend

Thomas Lamprecht t.lamprecht at proxmox.com
Mon Jan 27 09:54:56 CET 2020


On 1/16/20 4:40 PM, Stefan Reiter wrote:
> 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.

few general things:

1. wouldn't this belong before or in patch 03/10 to avoid temporary
   breakage possibility? I mean a user has to actively enable it so
   it could be OK, but still.

2. Doesn't this need a bump of the perversion for the machine? Else
   this fails on migration with due to the new option, which could
   be confusing/seem like a bug. Maybe only allow/add the whole custom
   thing with a bumped machine version?

> 
> Signed-off-by: Stefan Reiter <s.reiter at 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 f0b9e58..c2f6513 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -1098,6 +1098,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 4a5dfac..d7b9c09 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};
>      }
>  
> @@ -5231,8 +5239,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";
>  	}
>  
> @@ -5478,7 +5487,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);
>  	}
>  
> @@ -5491,13 +5500,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
>  
> @@ -5506,7 +5517,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);
>  }
> @@ -5780,7 +5792,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 $@;
> 





More information about the pve-devel mailing list