diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 31a6509166..bc6cf133d4 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -66,6 +66,7 @@ #include "backup_conf.h" #include "virutil.h" #include "virsecureerase.h" +#include "cpu/cpu_x86.h" #include #include @@ -6643,10 +6644,36 @@ qemuDomainDefCopy(virQEMUDriver *driver, } +typedef struct { + const char * const *added; + GStrv keep; +} qemuDomainDropAddedCPUFeaturesData; + + +static bool +qemuDomainDropAddedCPUFeatures(const char *name, + virCPUFeaturePolicy policy G_GNUC_UNUSED, + void *opaque) +{ + qemuDomainDropAddedCPUFeaturesData *data = opaque; + + if (!g_strv_contains(data->added, name)) + return true; + + if (data->keep && g_strv_contains((const char **) data->keep, name)) + return true; + + return false; +} + + int qemuDomainMakeCPUMigratable(virArch arch, - virCPUDef *cpu) + virCPUDef *cpu, + virCPUDef *origCPU) { + qemuDomainDropAddedCPUFeaturesData data = { 0 }; + if (cpu->mode != VIR_CPU_MODE_CUSTOM || !cpu->model || !ARCH_IS_X86(arch)) @@ -6664,6 +6691,25 @@ qemuDomainMakeCPUMigratable(virArch arch, return -1; } + if (virCPUx86GetAddedFeatures(cpu->model, &data.added) < 0) + return -1; + + /* Drop features marked as added in a cpu model, but only + * when they are not mentioned in origCPU, i.e., when they were not + * explicitly mentioned by the user. + */ + if (data.added) { + g_auto(GStrv) keep = NULL; + + if (origCPU) { + keep = virCPUDefListExplicitFeatures(origCPU); + data.keep = keep; + } + + if (virCPUDefFilterFeatures(cpu, qemuDomainDropAddedCPUFeatures, &data) < 0) + return -1; + } + return 0; } @@ -6843,7 +6889,7 @@ qemuDomainDefFormatBufInternal(virQEMUDriver *driver, } if (def->cpu && - qemuDomainMakeCPUMigratable(def->os.arch, def->cpu) < 0) + qemuDomainMakeCPUMigratable(def->os.arch, def->cpu, origCPU) < 0) return -1; /* Old libvirt doesn't understand