This is required to support custom CPU models, since the "cpu-models.conf" file is not versioned, and can be changed while a VM using a custom model is running. Changing the file in such a state can lead to a different "-cpu" argument on the receiving side.
This patch fixes this by passing the entire "-cpu" option (extracted from /proc/.../cmdline) as a "qm start" parameter. Note that this is only done if the VM to migrate is using a custom model (which we can check just fine, since the <vmid>.conf *is* versioned with pending changes), thus not breaking any live-migration directionality. Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- New in v6! Technically independant from the rest of the series, but live-migrating VMs with custom models would be broken in some cases. PVE/API2/Qemu.pm | 9 ++++++++- PVE/QemuMigrate.pm | 22 ++++++++++++++++++++++ PVE/QemuServer.pm | 14 ++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index ed4e522..c80d756 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -1969,6 +1969,11 @@ __PACKAGE__->register_method({ optional => 1, }, machine => get_standard_option('pve-qm-machine'), + 'force-cpu' => { + description => "Override QEMU's -cpu argument with the given string.", + type => 'string', + optional => 1, + }, targetstorage => { description => "Target storage for the migration. (Can be '1' to use the same storage id as on the source node.)", type => 'string', @@ -1989,6 +1994,7 @@ __PACKAGE__->register_method({ my $vmid = extract_param($param, 'vmid'); my $machine = extract_param($param, 'machine'); + my $force_cpu = extract_param($param, 'force-cpu'); my $get_root_param = sub { my $value = extract_param($param, $_[0]); @@ -2041,7 +2047,8 @@ __PACKAGE__->register_method({ syslog('info', "start VM $vmid: $upid\n"); PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom, undef, - $machine, $spice_ticket, $migration_network, $migration_type, $targetstorage); + $machine, $spice_ticket, $migration_network, $migration_type, + $targetstorage, $force_cpu); return; }; diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index d3e434c..5ac72cf 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -11,6 +11,8 @@ use PVE::Tools; use PVE::Cluster; use PVE::Storage; use PVE::QemuServer; +use PVE::QemuServer::CPUConfig; +use PVE::QemuServer::Helpers; use PVE::QemuServer::Machine; use PVE::QemuServer::Monitor qw(mon_cmd); use Time::HiRes qw( usleep ); @@ -219,7 +221,23 @@ sub prepare { $self->{forcemachine} = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf); + # To support custom CPU types, we keep QEMU's "-cpu" parameter intact. + # Since the parameter itself contains no reference to a custom model, + # this makes migration independent of changes to "cpu-models.conf". + if ($conf->{cpu}) { + my $cpuconf = PVE::QemuServer::CPUConfig::parse_cpu_conf_basic($conf->{cpu}); + if ($cpuconf && PVE::QemuServer::CPUConfig::is_custom_model($cpuconf->{cputype})) { + 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} =~ m/^((?>[+-]?[\w\-_=]+,?)+)$/; + $self->{forcecpu} = $1; + } + } } + my $loc_res = PVE::QemuServer::check_local_resources($conf, 1); if (scalar @$loc_res) { if ($self->{running} || !$self->{opts}->{force}) { @@ -573,6 +591,10 @@ sub phase2 { push @$cmd, '--machine', $self->{forcemachine}; } + if ($self->{forcecpu}) { + push @$cmd, '--force-cpu', $self->{forcecpu}; + } + if ($self->{online_local_volumes}) { push @$cmd, '--targetstorage', ($self->{opts}->{targetstorage} // '1'); } diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index f06da2a..fe68d89 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -3381,7 +3381,7 @@ sub query_understood_cpu_flags { } sub config_to_command { - my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_; + my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $force_cpu) = @_; my $cmd = []; my $globalFlags = []; @@ -3764,7 +3764,12 @@ sub config_to_command { push @$rtcFlags, 'base=localtime'; } - push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough); + if ($force_cpu) { + push @$cmd, '-cpu', $force_cpu; + } else { + push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, + $machine_version, $winversion, $gpu_passthrough); + } PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd); @@ -5118,7 +5123,8 @@ sub vmconfig_update_disk { sub vm_start { my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, - $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_; + $forcemachine, $spice_ticket, $migration_network, $migration_type, + $targetstorage, $force_cpu) = @_; PVE::QemuConfig->lock_config($vmid, sub { my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom); @@ -5204,7 +5210,7 @@ sub vm_start { print "Resuming suspended VM\n"; } - my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine); + my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine, $force_cpu); my $migration_ip; my $get_migration_ip = sub { -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel