diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 1734561215..2b0d641e78 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -167,6 +167,79 @@ virCPUCompare(virArch arch, } +/** virCPUCompareUnusable: + * @arch: CPU architecture + * @host: host CPU reported by the hypervisor + * @cpu: CPU to be compared with @host + * @blockers: NULL terminated list of features blocking usability of the CPU model from @cpu + * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE + * + * Check if @cpu can be run on @host when we know model used by @cpu is + * considered unusable by the hypervisor because it requires some features + * that cannot be provided on the host (the list of them is passed as + * @blockers) and/or @cpu requests additional features. The @cpu definition + * can still be compatible with @host if all @blockers are explicitly disabled + * and all explicitly requested features are supported by @host. + * + * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when + * the @cpu cannot be created on @host, or VIR_CPU_COMPARE_SUPERSET when the + * @cpu is compatible with @host CPU. If @failIncompatible is true, the + * function will return VIR_CPU_COMPARE_ERROR (and set VIR_ERR_CPU_INCOMPATIBLE + * error) when the two CPUs are incompatible. + */ +int +virCPUCompareUnusable(virArch arch, + const virCPUDef *host, + const virCPUDef *cpu, + char **blockers, + bool failIncompatible) +{ + g_autoptr(virCPUDef) expanded = NULL; + g_auto(virBuffer) features = VIR_BUFFER_INITIALIZER; + g_autofree char *str = NULL; + virCPUFeatureDef *feat; + char **blocker; + size_t i; + + for (blocker = blockers; *blocker; blocker++) { + if (!(feat = virCPUDefFindFeature(cpu, *blocker)) || + feat->policy != VIR_CPU_FEATURE_DISABLE) { + virBufferAddStr(&features, *blocker); + virBufferAddLit(&features, ", "); + } + } + + expanded = virCPUDefCopy(host); + if (virCPUExpandFeatures(arch, expanded) < 0) + return VIR_CPU_COMPARE_ERROR; + + for (i = 0; i < cpu->nfeatures; i++) { + if (cpu->features[i].policy != VIR_CPU_FEATURE_REQUIRE) + continue; + + if (!(feat = virCPUDefFindFeature(expanded, cpu->features[i].name)) || + feat->policy != VIR_CPU_FEATURE_REQUIRE) { + virBufferAddStr(&features, cpu->features[i].name); + virBufferAddLit(&features, ", "); + } + } + virBufferTrim(&features, ", "); + + if ((str = virBufferContentAndReset(&features))) { + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, + _("Host CPU does not provide required features: %1$s"), + str); + return VIR_CPU_COMPARE_ERROR; + } + + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + return VIR_CPU_COMPARE_SUPERSET; +} + + /** * cpuDecode: * diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index ceb6eb0944..ff68c5da2d 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -185,6 +185,13 @@ virCPUCompare(virArch arch, bool failIncompatible) ATTRIBUTE_NONNULL(3); +int +virCPUCompareUnusable(virArch arch, + const virCPUDef *host, + const virCPUDef *cpu, + char **blockers, + bool failIncompatible); + int cpuDecode (virCPUDef *cpu, const virCPUData *data, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 551cea989b..c1542847f4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1524,6 +1524,7 @@ virCPUBaseline; virCPUCheckFeature; virCPUCheckForbiddenFeatures; virCPUCompare; +virCPUCompareUnusable; virCPUCompareXML; virCPUConvertLegacy; virCPUCopyMigratable;