Add a new helper qemuProcessCheckS390CPU() in qemu_process.c that wraps the QMP query-cpu-model-comparison probe for s390x and returns a virCPUCompareResult directly. The helper filters out the special "type" responsible-property (which signals a CPU generation mismatch rather than a missing feature) before reporting incompatibility to the caller. When reporting incompatibility, the differing properties are listed in the error message when available. If no responsible-properties are returned (or all are filtered out), a generic incompatibility message is reported instead. Wire the helper into qemuProcessUpdateGuestCPU() so that s390x CPU model compatibility is checked for real domain start paths (migration, snapshot restore) when the QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON capability is present. The host CPU is passed as the first argument and the guest CPU as the second, matching qemuConnectCPUModelComparison(). The check is skipped in pretend mode (VIR_QEMU_PROCESS_START_PRETEND) since that path is used for command-line generation and does not involve a running QEMU instance. It is also skipped when the guest CPU definition has no model yet (for example host-model on a fresh start), since that model is resolved from the host CPU later and cannot be incompatible with it. Simplify qemuConnectCPUModelComparison() in qemu_driver.c to delegate directly to qemuProcessCheckS390CPU(). Signed-off-by: Rorie Reyes <rreyes@linux.ibm.com> --- src/qemu/qemu_driver.c | 23 ++----------- src/qemu/qemu_process.c | 75 +++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_process.h | 9 +++++ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 199eedca36..ef549a2c02 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12127,27 +12127,8 @@ qemuConnectCPUModelComparison(virQEMUCaps *qemuCaps, virCPUDef *cpu_b, bool failIncompatible) { - g_autoptr(qemuProcessQMP) proc = NULL; - virCPUCompareResult result; - - if (!(proc = qemuProcessQMPNew(virQEMUCapsGetBinary(qemuCaps), - libDir, runUid, runGid, false))) - return VIR_CPU_COMPARE_ERROR; - - if (qemuProcessQMPStart(proc) < 0) - return VIR_CPU_COMPARE_ERROR; - - result = qemuMonitorGetCPUModelComparison(proc->mon, cpu_a, cpu_b, NULL); - - if (result == VIR_CPU_COMPARE_ERROR) - return VIR_CPU_COMPARE_ERROR; - - if (failIncompatible && result == VIR_CPU_COMPARE_INCOMPATIBLE) { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); - return VIR_CPU_COMPARE_ERROR; - } - - return result; + return qemuProcessCheckS390CPU(qemuCaps, libDir, runUid, runGid, + cpu_a, cpu_b, failIncompatible); } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 3f1960f314..dfb9e0785a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6708,6 +6708,20 @@ qemuProcessUpdateGuestCPU(virDomainDef *def, VIR_QEMU_CAPS_HOST_CPU_FULL, true) < 0) return -1; + if (!(flags & VIR_QEMU_PROCESS_START_PRETEND) && + def->cpu->model && + ARCH_IS_S390(hostarch) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_COMPARISON)) { + virCPUDef *hvCPU = virQEMUCapsGetHostModel(qemuCaps, def->virtType, + VIR_QEMU_CAPS_HOST_CPU_REPORTED); + + if (hvCPU && hvCPU->fallback == VIR_CPU_FALLBACK_FORBID && + qemuProcessCheckS390CPU(qemuCaps, cfg->libDir, + cfg->user, cfg->group, + hvCPU, def->cpu, true) == VIR_CPU_COMPARE_ERROR) + 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 @@ -10589,6 +10603,67 @@ qemuProcessQMPStart(qemuProcessQMP *proc) } +virCPUCompareResult +qemuProcessCheckS390CPU(virQEMUCaps *qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + virCPUDef *cpu_a, + virCPUDef *cpu_b, + bool failIncompatible) +{ + g_autoptr(qemuProcessQMP) proc = NULL; + g_auto(GStrv) responsibleProps = NULL; + virCPUCompareResult result; + + if (!(proc = qemuProcessQMPNew(virQEMUCapsGetBinary(qemuCaps), + libDir, runUid, runGid, false))) + return VIR_CPU_COMPARE_ERROR; + + if (qemuProcessQMPStart(proc) < 0) + return VIR_CPU_COMPARE_ERROR; + + result = qemuMonitorGetCPUModelComparison(proc->mon, cpu_a, cpu_b, + &responsibleProps); + + if (result == VIR_CPU_COMPARE_ERROR) + return VIR_CPU_COMPARE_ERROR; + + if (result == VIR_CPU_COMPARE_IDENTICAL || result == VIR_CPU_COMPARE_SUPERSET) + return result; + + /* result is VIR_CPU_COMPARE_INCOMPATIBLE — filter out the special "type" + * property which signals a CPU generation mismatch rather than a missing + * feature and should not be reported as such to the user. */ + if (responsibleProps) { + size_t i, j; + for (i = 0, j = 0; responsibleProps[i]; i++) { + if (STRNEQ(responsibleProps[i], "type")) + responsibleProps[j++] = responsibleProps[i]; + else + g_free(responsibleProps[i]); + } + responsibleProps[j] = NULL; + } + + if (failIncompatible) { + if (responsibleProps && responsibleProps[0]) { + g_autofree char *props = g_strjoinv(", ", responsibleProps); + + virReportError(VIR_ERR_CPU_INCOMPATIBLE, + _("guest CPU model is not compatible with the destination host CPU model, differing properties: %1$s"), + props); + } else { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", + _("guest CPU model is not compatible with the destination host CPU model")); + } + return VIR_CPU_COMPARE_ERROR; + } + + return VIR_CPU_COMPARE_INCOMPATIBLE; +} + + void qemuProcessHandleNbdkitExit(qemuNbdkitProcess *nbdkit, virDomainObj *vm) diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 5d8f1f89d5..d9dd5e185e 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -258,6 +258,15 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuProcessQMP, qemuProcessQMPFree); int qemuProcessQMPStart(qemuProcessQMP *proc); +virCPUCompareResult +qemuProcessCheckS390CPU(virQEMUCaps *qemuCaps, + const char *libDir, + uid_t runUid, + gid_t runGid, + virCPUDef *cpu_a, + virCPUDef *cpu_b, + bool failIncompatible); + void qemuProcessCleanupMigrationJob(virQEMUDriver *driver, virDomainObj *vm); -- 2.48.1