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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list