Features removed from a CPU model are marked with "removed='yes'"
attribute in the CPU map. Such features will always be present in a CPU
definition produced by libvirt regardless on their state. In other words
a running domain (even saved in a file) will always explicitly contain
states of all features removed from the specified CPU model. This
enables migration to older libvirt which would otherwise think the
affected features should be enabled as they are still included in the
CPU model in the older version of CPU map. Migration from an old libvirt
to a new one would be broken as the new libvirt would think the removed
features should be disabled (because they are not included in the CPU
model anymore), which might not be the case on the source host. Thus we
were refusing to remove CPU features unless they were never working and
no domain could even be running with those features enabled.
This patch removes the limitation. When handling CPU definitions with
missing features marked as removed in the specified CPU model, we know
whether it comes from a running domain, in which case it must have been
created by older libvirt where the missing CPU features were not removed
yet. This means the features must have been enabled on the source and we
can automatically fix the definition by adding the missing features with
correct states.
We can safely remove any CPU feature from our CPU models now, but it
should only be used for features removed from all versions of a given
CPU model in QEMU because unversioned models correspond to v1.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/qemu/qemu_process.c | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d5c5342966..d0f8176b2c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -6270,6 +6270,7 @@ qemuProcessUpdateGuestCPU(virDomainDef *def,
if (def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH &&
def->cpu->mode != VIR_CPU_MODE_MAXIMUM) {
g_autoptr(virDomainCapsCPUModels) cpuModels = NULL;
+ virCPUFeaturePolicy removedPolicy = VIR_CPU_FEATURE_DISABLE;
if (def->cpu->check == VIR_CPU_CHECK_PARTIAL &&
!virQEMUCapsIsCPUUsable(qemuCaps, def->virtType, def->cpu) &&
@@ -6279,10 +6280,22 @@ qemuProcessUpdateGuestCPU(virDomainDef *def,
def->cpu, true) < 0)
return -1;
+ /* When starting a fresh domain we disable all features removed from
+ * the specified CPU model to make sure they are only used if
+ * explicitly requested. But when we are restoring a previously running
+ * domain (migration, snapshot, ...) all removed features were already
+ * explicitly listed in the CPU definition and if we found a removed
+ * feature which is missing it must have been removed later and must be
+ * enabled rather than disabled here match the state described by older
+ * libvirt.
+ */
+ if (!(flags & VIR_QEMU_PROCESS_START_NEW))
+ removedPolicy = VIR_CPU_FEATURE_REQUIRE;
+
if (virCPUUpdate(def->os.arch, def->cpu,
virQEMUCapsGetHostModel(qemuCaps, def->virtType,
VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE),
- VIR_CPU_FEATURE_DISABLE) < 0)
+ removedPolicy) < 0)
return -1;
cpuModels = virQEMUCapsGetCPUModels(qemuCaps, def->virtType, NULL, NULL);
@@ -8877,13 +8890,27 @@ qemuProcessRefreshCPU(virQEMUDriver *driver,
g_autoptr(virCPUDef) host = NULL;
g_autoptr(virCPUDef) hostmig = NULL;
g_autoptr(virCPUDef) cpu = NULL;
+ virCPUFeaturePolicy removedPolicy;
- if (!virQEMUCapsGuestIsNative(driver->hostarch, vm->def->os.arch))
- return 0;
+ /* When reconnecting to a running domain, we know all features marked as
+ * removed from a CPU model were already explicitly mentioned in the
+ * definition. If any removed features are missing, they must have been
+ * removed after the domain was started and thus they have to be enabled
+ * (otherwise they would be explicitly listed as disabled).
+ */
+ removedPolicy = VIR_CPU_FEATURE_REQUIRE;
if (!vm->def->cpu)
return 0;
+ if (vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM &&
+ vm->def->cpu->model &&
+ virCPUUpdate(vm->def->os.arch, vm->def->cpu, NULL, removedPolicy)
< 0)
+ return -1;
+
+ if (!virQEMUCapsGuestIsNative(driver->hostarch, vm->def->os.arch))
+ return 0;
+
if (qemuProcessRefreshCPUMigratability(vm, VIR_ASYNC_JOB_NONE) < 0)
return -1;
@@ -8915,8 +8942,7 @@ qemuProcessRefreshCPU(virQEMUDriver *driver,
virCPUDefCopyModelFilter(cpu, hostmig, false, virQEMUCapsCPUFilterFeatures,
&host->arch);
- if (virCPUUpdate(vm->def->os.arch, vm->def->cpu, cpu,
- VIR_CPU_FEATURE_DISABLE) < 0)
+ if (virCPUUpdate(vm->def->os.arch, vm->def->cpu, cpu, removedPolicy)
< 0)
return -1;
if (qemuProcessUpdateCPU(vm, VIR_ASYNC_JOB_NONE) < 0)
--
2.44.0