diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index e7b684d7..7aa0b8f8 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -4667,13 +4667,18 @@ __PACKAGE__->register_method({ }, description => "List local resources (e.g. pci, usb) that block migration." }, + # FIXME: remove with 9.0 'mapped-resources' => { type => 'array', items => { type => 'string', description => "A mapped resource", }, - description => "List of mapped resources e.g. pci, usb" + description => "List of mapped resources e.g. pci, usb. Deprecated, use 'mapped-resource-info' instead." + }, + 'mapped-resource-info' => { + type => 'object', + description => "Object of mapped resources with additional information such if they're live migratable.", }, }, }, @@ -4738,7 +4743,8 @@ __PACKAGE__->register_method({ $res->{local_disks} = [ values %$local_disks ];; $res->{local_resources} = $local_resources; - $res->{'mapped-resources'} = $mapped_resources; + $res->{'mapped-resources'} = [ sort keys $mapped_resources->%* ]; + $res->{'mapped-resource-info'} = $mapped_resources; return $res; diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index c2e36334..6909fc82 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -229,7 +229,7 @@ sub prepare { my ($loc_res, $mapped_res, $missing_mappings_by_node) = PVE::QemuServer::check_local_resources($conf, $running, 1); my $blocking_resources = []; for my $res ($loc_res->@*) { - if (!grep($res, $mapped_res->@*)) { + if (!defined($mapped_res->{$res})) { push $blocking_resources->@*, $res; } } @@ -241,12 +241,20 @@ sub prepare { } } - if (scalar($mapped_res->@*)) { + if (scalar(keys $mapped_res->%*)) { my $missing_mappings = $missing_mappings_by_node->{$self->{node}}; - if ($running) { - die "can't migrate running VM which uses mapped devices: " . join(", ", $mapped_res->@*) . "\n"; - } elsif (scalar($missing_mappings->@*)) { - die "can't migrate to '$self->{node}': missing mapped devices " . join(", ", $missing_mappings->@*) . "\n"; + my $missing_live_mappings = []; + for my $key (sort keys $mapped_res->%*) { + my $res = $mapped_res->{$key}; + my $name = "$key:$res->{name}"; + push $missing_live_mappings->@*, $name if !$res->{'live-migration'}; + } + if (scalar($missing_mappings->@*)) { + my $missing = join(", ", $missing_mappings->@*); + die "can't migrate to '$self->{node}': missing mapped devices $missing\n"; + } elsif ($running && scalar($missing_live_mappings->@*)) { + my $missing = join(", ", $missing_live_mappings->@*); + die "can't live migrate running VM which uses following mapped devices: $missing\n"; } else { $self->log('info', "migrating VM which uses mapped local devices"); } diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 155432d3..2e72e2d6 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -2472,7 +2472,7 @@ sub check_local_resources { my ($conf, $state, $noerr) = @_; my @loc_res = (); - my $mapped_res = []; + my $mapped_res = {}; my @non_migratable_resources = check_non_migratable_resources($conf, $state, $noerr); push(@loc_res, @non_migratable_resources); @@ -2507,16 +2507,17 @@ sub check_local_resources { if ($k =~ m/^usb/) { my $entry = parse_property_string('pve-qm-usb', $conf->{$k}); next if $entry->{host} && $entry->{host} =~ m/^spice$/i; - if ($entry->{mapping}) { - $add_missing_mapping->('usb', $k, $entry->{mapping}); - push @$mapped_res, $k; + if (my $name = $entry->{mapping}) { + $add_missing_mapping->('usb', $k, $name); + $mapped_res->{$k} = { name => $name }; } } if ($k =~ m/^hostpci/) { my $entry = parse_property_string('pve-qm-hostpci', $conf->{$k}); - if ($entry->{mapping}) { - $add_missing_mapping->('pci', $k, $entry->{mapping}); - push @$mapped_res, $k; + if (my $name = $entry->{mapping}) { + $add_missing_mapping->('pci', $k, $name); + my $mapped_device = { name => $name }; + $mapped_res->{$k} = $mapped_device; # don't add mapped devices as blocker for offline migration but still iterate over # all mappings above to collect on which nodes they are available.