diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index be90797c436f9cbfbf54defd9fde8a4dc1ad1002..15ba4f17922cf0769b142fc568bef1485a7636ef 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -300,6 +300,8 @@ typedef enum { was denied */ VIR_ERR_DBUS_SERVICE = 89, /* error from a dbus service */ VIR_ERR_STORAGE_VOL_EXIST = 90, /* the storage vol already exists */ + VIR_ERR_CPU_INCOMPATIBLE = 91, /* given CPU is incompatible with host + CPU*/ } virErrorNumber; /** diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index bb9bcb7916c614e6225cecfc35e83ff20d350256..9bece84c2c007aba91fb023f0f5b61dcd815f0b6 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1332,7 +1332,7 @@ bhyveConnectCompareCPU(virConnectPtr conn, VIR_WARN("cannot get host CPU capabilities"); ret = VIR_CPU_COMPARE_INCOMPATIBLE; } else { - ret = cpuCompareXML(caps->host.cpu, xmlDesc); + ret = cpuCompareXML(caps->host.cpu, xmlDesc, false); } cleanup: diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c3d66dd374daf15fafb7e6af6d539b9673f4ba82..08bec5e56add00abc4edad96baf2ef94197cf1dc 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -92,7 +92,8 @@ cpuGetSubDriver(virArch arch) */ virCPUCompareResult cpuCompareXML(virCPUDefPtr host, - const char *xml) + const char *xml, + bool failIncompatible) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; @@ -108,7 +109,7 @@ cpuCompareXML(virCPUDefPtr host, if (cpu == NULL) goto cleanup; - ret = cpuCompare(host, cpu); + ret = cpuCompare(host, cpu, failIncompatible); cleanup: virCPUDefFree(cpu); @@ -134,7 +135,8 @@ cpuCompareXML(virCPUDefPtr host, */ virCPUCompareResult cpuCompare(virCPUDefPtr host, - virCPUDefPtr cpu) + virCPUDefPtr cpu, + bool failIncompatible) { struct cpuArchDriver *driver; @@ -156,7 +158,7 @@ cpuCompare(virCPUDefPtr host, return VIR_CPU_COMPARE_ERROR; } - return driver->compare(host, cpu); + return driver->compare(host, cpu, failIncompatible); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index e9f271330b16f096c8c8684ac3bdb24484d29569..339964ce3ae4102996ec01cafb8c8f16cbf667a2 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -46,7 +46,8 @@ struct _virCPUData { typedef virCPUCompareResult (*cpuArchCompare) (virCPUDefPtr host, - virCPUDefPtr cpu); + virCPUDefPtr cpu, + bool failIncompatible); typedef int (*cpuArchDecode) (virCPUDefPtr cpu, @@ -119,12 +120,14 @@ struct cpuArchDriver { extern virCPUCompareResult cpuCompareXML(virCPUDefPtr host, - const char *xml) + const char *xml, + bool failIncompatible) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); extern virCPUCompareResult cpuCompare (virCPUDefPtr host, - virCPUDefPtr cpu) + virCPUDefPtr cpu, + bool failIncompatible) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); extern int diff --git a/src/cpu/cpu_aarch64.c b/src/cpu/cpu_aarch64.c index 7255d9fdf638d516974dd429e44efa6e240ebf0e..6346f9bd5e5814fc258a237c31e2dc20c9ed71bf 100644 --- a/src/cpu/cpu_aarch64.c +++ b/src/cpu/cpu_aarch64.c @@ -110,7 +110,8 @@ AArch64Baseline(virCPUDefPtr *cpus, static virCPUCompareResult AArch64Compare(virCPUDefPtr host ATTRIBUTE_UNUSED, - virCPUDefPtr cpu ATTRIBUTE_UNUSED) + virCPUDefPtr cpu ATTRIBUTE_UNUSED, + bool failIncompatible ATTRIBUTE_UNUSED) { return VIR_CPU_COMPARE_IDENTICAL; } diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 39e8f128938c0071f6b2e86ac304da8b515fe665..ec755bd157e56eaef6f9cf56da20d730a5319add 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -113,7 +113,8 @@ ArmBaseline(virCPUDefPtr *cpus, static virCPUCompareResult ArmCompare(virCPUDefPtr host ATTRIBUTE_UNUSED, - virCPUDefPtr cpu ATTRIBUTE_UNUSED) + virCPUDefPtr cpu ATTRIBUTE_UNUSED, + bool failMessages ATTRIBUTE_UNUSED) { return VIR_CPU_COMPARE_IDENTICAL; } diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c index f115c40d3e981fdba5a72ada1171fad56ae02009..d6890c0be46a25144c1a22f33acdc2267099f09c 100644 --- a/src/cpu/cpu_generic.c +++ b/src/cpu/cpu_generic.c @@ -57,17 +57,20 @@ genericHashFeatures(virCPUDefPtr cpu) static virCPUCompareResult genericCompare(virCPUDefPtr host, - virCPUDefPtr cpu) + virCPUDefPtr cpu, + bool failIncompatible) { - virHashTablePtr hash; + virHashTablePtr hash = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; size_t i; unsigned int reqfeatures; if ((cpu->arch != VIR_ARCH_NONE && host->arch != cpu->arch) || - STRNEQ(host->model, cpu->model)) - return VIR_CPU_COMPARE_INCOMPATIBLE; + STRNEQ(host->model, cpu->model)) { + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } if ((hash = genericHashFeatures(host)) == NULL) goto cleanup; @@ -102,6 +105,10 @@ genericCompare(virCPUDefPtr host, cleanup: virHashFree(hash); + if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { + ret = VIR_CPU_COMPARE_ERROR; + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + } return ret; } diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 05fa55b88fbec39469386522bc505c452988316f..67cb9ff61ad5bc88a89fc525cb4784f3c742af30 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -440,13 +440,19 @@ ppcCompute(virCPUDefPtr host, static virCPUCompareResult ppcCompare(virCPUDefPtr host, - virCPUDefPtr cpu) + virCPUDefPtr cpu, + bool failIncompatible) { if ((cpu->arch == VIR_ARCH_NONE || host->arch == cpu->arch) && STREQ(host->model, cpu->model)) return VIR_CPU_COMPARE_IDENTICAL; - return VIR_CPU_COMPARE_INCOMPATIBLE; + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + return VIR_CPU_COMPARE_ERROR; + } else { + return VIR_CPU_COMPARE_INCOMPATIBLE; + } } static int diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 72c5216f012dac09edbefdf5b194f1247ed3aff5..235fa49483bf80b25cf9e1e564c5b6457190d94d 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1463,9 +1463,25 @@ x86Compute(virCPUDefPtr host, static virCPUCompareResult x86Compare(virCPUDefPtr host, - virCPUDefPtr cpu) + virCPUDefPtr cpu, + bool failIncomaptible) { - return x86Compute(host, cpu, NULL, NULL); + virCPUCompareResult ret; + char *message = NULL; + + ret = x86Compute(host, cpu, NULL, &message); + + if (failIncomaptible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { + ret = VIR_CPU_COMPARE_ERROR; + if (message) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message); + } else { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + } + } + VIR_FREE(message); + + return ret; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 22699c10e8e3d497f8d276dbe62439832e5c4881..3c23fc7cf7763494e9ba378b0a59fef6342dbee5 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11528,7 +11528,7 @@ qemuConnectCompareCPU(virConnectPtr conn, VIR_WARN("cannot get host CPU capabilities"); ret = VIR_CPU_COMPARE_INCOMPATIBLE; } else { - ret = cpuCompareXML(caps->host.cpu, xmlDesc); + ret = cpuCompareXML(caps->host.cpu, xmlDesc, false); } cleanup: diff --git a/src/util/virerror.c b/src/util/virerror.c index e0bc970e3217d14d9c526d3a98003cccb38cf83b..6bd3d09cfdeb884ccb5a0c72b1f5f4cb9eb4c880 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1277,6 +1277,12 @@ virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("error from service: %s"); break; + case VIR_ERR_CPU_INCOMPATIBLE: + if (info == NULL) + errmsg = _("the CPU is incompatible with host CPU"); + else + errmsg = _("the CPU is incompatible with host CPU: %s"); + break; } return errmsg; } diff --git a/tests/cputest.c b/tests/cputest.c index 3766c2f2df43d9b554bf28ace241cd2c623e2f2f..38cd71e82154e723cfb1e4361e3c41412ef4e98a 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -228,7 +228,7 @@ cpuTestCompare(const void *arg) !(cpu = cpuTestLoadXML(data->arch, data->name))) goto cleanup; - result = cpuCompare(host, cpu); + result = cpuCompare(host, cpu, false); if (data->result == VIR_CPU_COMPARE_ERROR) virResetLastError(); @@ -357,7 +357,7 @@ cpuTestBaseline(const void *arg) for (i = 0; i < ncpus; i++) { virCPUCompareResult cmp; - cmp = cpuCompare(cpus[i], baseline); + cmp = cpuCompare(cpus[i], baseline, false); if (cmp != VIR_CPU_COMPARE_SUPERSET && cmp != VIR_CPU_COMPARE_IDENTICAL) { if (virTestGetVerbose()) {