When guest CPU definition uses VIR_CPU_CHECK_FULL checks, we need to
make sure QEMU does not add or remove any features.
https://bugzilla.redhat.com/show_bug.cgi?id=822148
https://bugzilla.redhat.com/show_bug.cgi?id=824989
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/cpu/cpu.c | 3 ++-
src/cpu/cpu_x86.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 992a0339c..1461190ba 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -722,7 +722,8 @@ virCPUUpdate(virArch arch,
* hypervisor
*
* Update custom mode CPU according to the virtual CPU created by the
- * hypervisor.
+ * hypervisor. The function refuses to update the CPU in case cpu->check is set
+ * to VIR_CPU_CHECK_FULL.
*
* Returns -1 on error,
* 0 when the CPU was successfully updated,
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index a43bb2bdf..9e208b094 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -2686,6 +2686,10 @@ virCPUx86UpdateLive(virCPUDefPtr cpu,
virCPUx86ModelPtr model = NULL;
virCPUx86Data enabled = VIR_CPU_X86_DATA_INIT;
virCPUx86Data disabled = VIR_CPU_X86_DATA_INIT;
+ virBuffer bufAdded = VIR_BUFFER_INITIALIZER;
+ virBuffer bufRemoved = VIR_BUFFER_INITIALIZER;
+ char *added = NULL;
+ char *removed = NULL;
size_t i;
int ret = -1;
@@ -2709,28 +2713,70 @@ virCPUx86UpdateLive(virCPUDefPtr cpu,
virCPUx86FeaturePtr feature = map->features[i];
if (x86DataIsSubset(&enabled, &feature->data)) {
- VIR_DEBUG("Adding feature '%s' enabled by the hypervisor",
- feature->name);
- if (virCPUDefUpdateFeature(cpu, feature->name,
- VIR_CPU_FEATURE_REQUIRE) < 0)
+ VIR_DEBUG("Feature '%s' enabled by the hypervisor",
feature->name);
+ if (cpu->check == VIR_CPU_CHECK_FULL)
+ virBufferAsprintf(&bufAdded, "%s,", feature->name);
+ else if (virCPUDefUpdateFeature(cpu, feature->name,
+ VIR_CPU_FEATURE_REQUIRE) < 0)
goto cleanup;
}
if (x86DataIsSubset(&disabled, &feature->data)) {
- VIR_DEBUG("Removing feature '%s' disabled by the
hypervisor",
- feature->name);
- if (virCPUDefUpdateFeature(cpu, feature->name,
- VIR_CPU_FEATURE_DISABLE) < 0)
+ VIR_DEBUG("Feature '%s' disabled by the hypervisor",
feature->name);
+ if (cpu->check == VIR_CPU_CHECK_FULL)
+ virBufferAsprintf(&bufRemoved, "%s,", feature->name);
+ else if (virCPUDefUpdateFeature(cpu, feature->name,
+ VIR_CPU_FEATURE_DISABLE) < 0)
goto cleanup;
}
}
+ virBufferTrim(&bufAdded, ",", -1);
+ virBufferTrim(&bufRemoved, ",", -1);
+
+ if (virBufferCheckError(&bufAdded) < 0 ||
+ virBufferCheckError(&bufRemoved) < 0)
+ goto cleanup;
+
+ added = virBufferContentAndReset(&bufAdded);
+ removed = virBufferContentAndReset(&bufRemoved);
+
+ if (added || removed) {
+ if (added && removed)
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("guest CPU doesn't match specification: "
+ "extra features: %s, missing features: %s"),
+ added, removed);
+ else if (added)
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("guest CPU doesn't match specification: "
+ "extra features: %s"),
+ added);
+ else
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("guest CPU doesn't match specification: "
+ "missing features: %s"),
+ removed);
+ goto cleanup;
+ }
+
+ if (cpu->check == VIR_CPU_CHECK_FULL &&
+ !x86DataIsEmpty(&disabled)) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("guest CPU doesn't match specification"));
+ goto cleanup;
+ }
+
ret = 0;
cleanup:
x86ModelFree(model);
virCPUx86DataClear(&enabled);
virCPUx86DataClear(&disabled);
+ VIR_FREE(added);
+ VIR_FREE(removed);
+ virBufferFreeAndReset(&bufAdded);
+ virBufferFreeAndReset(&bufRemoved);
return ret;
}
--
2.12.0