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> --- PVE/API2/Qemu.pm | 8 +++++++- PVE/QemuMigrate.pm | 21 +++++++++++++++++++++ PVE/QemuServer.pm | 13 +++++++++---- PVE/QemuServer/CPUConfig.pm | 2 ++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index ef8a7c3..80fd7ea 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -2024,6 +2024,11 @@ __PACKAGE__->register_method({ optional => 1, }, machine => get_standard_option('pve-qemu-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', @@ -2052,6 +2057,7 @@ __PACKAGE__->register_method({ my $timeout = extract_param($param, 'timeout'); 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]); @@ -2113,7 +2119,7 @@ __PACKAGE__->register_method({ PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock, $migratedfrom, undef, $machine, $spice_ticket, $migration_network, $migration_type, $targetstorage, $timeout, - $nbd_protocol_version); + $nbd_protocol_version, $force_cpu); return; }; diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index 9cff64d..0604e33 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -17,6 +17,7 @@ use PVE::ReplicationState; use PVE::Storage; use PVE::Tools; +use PVE::QemuServer::CPUConfig; use PVE::QemuServer::Drive; use PVE::QemuServer::Helpers qw(min_version); use PVE::QemuServer::Machine; @@ -227,7 +228,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} =~ $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re; + $self->{forcecpu} = $1; + } + } } + my $loc_res = PVE::QemuServer::check_local_resources($conf, 1); if (scalar @$loc_res) { if ($self->{running} || !$self->{opts}->{force}) { @@ -645,6 +662,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 a3e3269..98c2a9a 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -2911,7 +2911,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 = []; @@ -3311,7 +3311,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); @@ -4706,7 +4711,7 @@ sub vmconfig_update_disk { sub vm_start { my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused, $forcemachine, $spice_ticket, $migration_network, $migration_type, - $targetstorage, $timeout, $nbd_protocol_version) = @_; + $targetstorage, $timeout, $nbd_protocol_version, $force_cpu) = @_; PVE::QemuConfig->lock_config($vmid, sub { my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom); @@ -4802,7 +4807,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 { diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm index 8a55739..4dcc6dc 100644 --- a/PVE/QemuServer/CPUConfig.pm +++ b/PVE/QemuServer/CPUConfig.pm @@ -106,6 +106,8 @@ my @supported_cpu_flags = ( my $cpu_flag_supported_re = qr/([+-])(@{[join('|', @supported_cpu_flags)]})/; my $cpu_flag_any_re = qr/([+-])([a-zA-Z0-9\-_\.]+)/; +our $qemu_cmdline_cpu_re = qr/^((?>[+-]?[\w\-_=]+,?)+)$/; + my $cpu_fmt = { cputype => { description => "Emulated CPU type. Can be default or custom name (custom model names must be prefixed with 'custom-').", -- 2.26.0 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel