qemuDomainMakeCPUMigratable() strips features marked added='yes' (in
src/cpu_map/x86_*.xml) from the migration cookie when the source CPU
was specified as host-model. The intent was libvirt-protocol compat
with older destinations; the cost is guest CPU compat, paid silently
on every migration.

Every Intel x86 CPU model from Westmere through Sapphire Rapids
carries 60+ added='yes' features, including
vmx-exit-load-perf-global-ctrl and vmx-entry-load-perf-global-ctrl
that control the LOAD_IA32_PERF_GLOBAL_CTRL allowed-1 bits of
MSR_IA32_VMX_{EXIT,ENTRY}_CTLS. A host-model live migration on any
of these models drops those features from the destination's qemu
argv. Modern qemu gates the nested VMX capability MSRs on the
explicit -cpu list, so the guest's MSR view shifts.

Linux distributions that load kvm_intel by default snapshot those
MSRs at module-load time and validate every newly online CPU
against that snapshot. An automated test that boots a guest,
live-migrates it, and hot-plugs additional vCPUs reliably trips

  kvm_intel: Inconsistent VMCS config on CPU N
  kvm: enabling virtualization on CPUN failed
  smpboot: CPU N is now offline

the guest agent's online attempt returns -EIO and the hot-plug
fails. Live migration must preserve the guest's CPU specification
bit for bit -- this is a hard contract, not an optimisation target.

Drop the strip. If a destination libvirt does not know a feature in
the cookie, its parser rejects the migration with a precise
unknown-feature error: operators can upgrade or narrow the source
CPU definition. Either is visible; the status quo is not.

This effectively reverts 14d3517410 ("qemu: domain: Drop added
features from migratable CPU") together with its follow-up
aae8a5774b ("qemu: Drop vmx-* from migratable CPU model only when
origCPU is set"), and removes the now-unused origCPU plumbing in
qemuDomainMakeCPUMigratable() and its callers.

Signed-off-by: Denis V. Lunev <[email protected]>
---
 src/qemu/qemu_domain.c           | 46 ++------------------------------
 src/qemu/qemu_domain.h           |  3 +--
 src/qemu/qemu_migration_cookie.c |  5 +---
 3 files changed, 4 insertions(+), 50 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 84c8645259..eccd279bbe 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5307,36 +5307,10 @@ 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 *origCPU)
+                            virCPUDef *cpu)
 {
-    qemuDomainDropAddedCPUFeaturesData data = { 0 };
-
     if (cpu->mode != VIR_CPU_MODE_CUSTOM ||
         !cpu->model ||
         !ARCH_IS_X86(arch))
@@ -5353,22 +5327,6 @@ qemuDomainMakeCPUMigratable(virArch arch,
         virCPUDefUpdateFeature(cpu, "pconfig", VIR_CPU_FEATURE_DISABLE);
     }
 
-    if (origCPU) {
-        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 = virCPUDefListExplicitFeatures(origCPU);
-            data.keep = keep;
-
-            virCPUDefFilterFeatures(cpu, qemuDomainDropAddedCPUFeatures, 
&data);
-        }
-    }
-
     return 0;
 }
 
@@ -5569,7 +5527,7 @@ qemuDomainDefFormatBufInternal(virQEMUDriver *driver,
         }
 
         if (def->cpu &&
-            qemuDomainMakeCPUMigratable(def->os.arch, def->cpu, origCPU) < 0)
+            qemuDomainMakeCPUMigratable(def->os.arch, def->cpu) < 0)
             return -1;
 
         /* Old libvirt doesn't understand <audio> elements so
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index b321a64e96..0600af8b7c 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -1066,8 +1066,7 @@ qemuDomainValidateActualNetDef(const virDomainNetDef *net,
 
 int
 qemuDomainMakeCPUMigratable(virArch arch,
-                            virCPUDef *cpu,
-                            virCPUDef *origCPU);
+                            virCPUDef *cpu);
 
 int
 qemuDomainInitializePflashStorageSource(virDomainObj *vm,
diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c
index 7311a8294b..ebc2072ab0 100644
--- a/src/qemu/qemu_migration_cookie.c
+++ b/src/qemu/qemu_migration_cookie.c
@@ -535,15 +535,12 @@ static int
 qemuMigrationCookieAddCPU(qemuMigrationCookie *mig,
                           virDomainObj *vm)
 {
-    qemuDomainObjPrivate *priv = vm->privateData;
-
     if (mig->cpu)
         return 0;
 
     mig->cpu = virCPUDefCopy(vm->def->cpu);
 
-    if (qemuDomainMakeCPUMigratable(vm->def->os.arch, mig->cpu,
-                                    priv->origCPU) < 0)
+    if (qemuDomainMakeCPUMigratable(vm->def->os.arch, mig->cpu) < 0)
         return -1;
 
     mig->flags |= QEMU_MIGRATION_COOKIE_CPU;
-- 
2.51.0

Reply via email to