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