From a1adfb0f066149f1aab52613d5e67e8e9da0d489 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Thu, 21 Apr 2016 13:08:12 +0200 Subject: [PATCH] qemu: Add support for unavailable-features QEMU 2.8.0 adds support for unavailable-features in query-cpu-definitions reply. The unavailable-features array lists CPU features which prevent a corresponding CPU model from being usable on current host. It can only be used when all the unavailable features are disabled. Empty array means the CPU model can be used without modifications. We can use unavailable-features for providing CPU model usability info in domain capabilities XML: ... Skylake-Client ... qemu64 qemu32 phenom pentium3 pentium2 pentium n270 kvm64 kvm32 coreduo core2duo athlon Westmere Skylake-Client ... ... Signed-off-by: Jiri Denemark --- src/qemu/qemu_capabilities.c | 39 ++++-- src/qemu/qemu_capabilities.h | 3 +- src/qemu/qemu_monitor.h | 1 + src/qemu/qemu_monitor_json.c | 18 +++ .../qemu_2.8.0-tcg.x86_64.xml | 58 ++++----- .../qemu_2.8.0.x86_64.xml | 58 ++++----- .../caps_2.8.0.x86_64.xml | 120 +++++++++--------- tests/qemumonitorjsontest.c | 27 +++- tests/qemuxml2argvtest.c | 24 ++-- 9 files changed, 207 insertions(+), 141 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 3581c2d723..ad9451e8f8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2348,7 +2348,8 @@ int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, virDomainVirtType type, const char **name, - size_t count) + size_t count, + virDomainCapsCPUUsable usable) { size_t i; virDomainCapsCPUModelsPtr cpus = NULL; @@ -2369,8 +2370,7 @@ virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, } for (i = 0; i < count; i++) { - if (virDomainCapsCPUModelsAdd(cpus, name[i], -1, - VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) + if (virDomainCapsCPUModelsAdd(cpus, name[i], -1, usable) < 0) return -1; } @@ -2786,9 +2786,14 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, qemuCaps->kvmCPUModels = models; for (i = 0; i < ncpus; i++) { - if (virDomainCapsCPUModelsAddSteal(models, - &cpus[i]->name, - VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) + virDomainCapsCPUUsable usable = VIR_DOMCAPS_CPU_USABLE_UNKNOWN; + + if (cpus[i]->usable == VIR_TRISTATE_BOOL_YES) + usable = VIR_DOMCAPS_CPU_USABLE_YES; + else if (cpus[i]->usable == VIR_TRISTATE_BOOL_NO) + usable = VIR_DOMCAPS_CPU_USABLE_NO; + + if (virDomainCapsCPUModelsAddSteal(models, &cpus[i]->name, usable) < 0) goto cleanup; } @@ -3099,14 +3104,23 @@ virQEMUCapsLoadCPUModels(virQEMUCapsPtr qemuCaps, qemuCaps->tcgCPUModels = cpus; for (i = 0; i < n; i++) { + int usable = VIR_DOMCAPS_CPU_USABLE_UNKNOWN; + + if ((str = virXMLPropString(nodes[i], "usable")) && + (usable = virDomainCapsCPUUsableTypeFromString(str)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown value '%s' in attribute 'usable'"), str); + goto cleanup; + } + VIR_FREE(str); + if (!(str = virXMLPropString(nodes[i], "name"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing cpu name in QEMU capabilities cache")); goto cleanup; } - if (virDomainCapsCPUModelsAddSteal(cpus, &str, - VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) + if (virDomainCapsCPUModelsAddSteal(cpus, &str, usable) < 0) goto cleanup; } @@ -3385,8 +3399,15 @@ virQEMUCapsFormatCPUModels(virQEMUCapsPtr qemuCaps, return; for (i = 0; i < cpus->nmodels; i++) { + virDomainCapsCPUModelPtr cpu = cpus->models + i; + virBufferAsprintf(buf, "\n", cpus->models[i].name); + virBufferEscapeString(buf, "name='%s'", cpu->name); + if (cpu->usable) { + virBufferAsprintf(buf, " usable='%s'", + virDomainCapsCPUUsableTypeToString(cpu->usable)); + } + virBufferAddLit(buf, "/>\n"); } } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6d57ffb7ca..b3175a5211 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -433,7 +433,8 @@ unsigned int virQEMUCapsGetKVMVersion(virQEMUCapsPtr qemuCaps); int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, virDomainVirtType type, const char **name, - size_t count); + size_t count, + virDomainCapsCPUUsable usable); int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, virDomainVirtType type, char ***names, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 100730bae4..f1ddb6c125 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -916,6 +916,7 @@ typedef struct _qemuMonitorCPUDefInfo qemuMonitorCPUDefInfo; typedef qemuMonitorCPUDefInfo *qemuMonitorCPUDefInfoPtr; struct _qemuMonitorCPUDefInfo { + virTristateBool usable; char *name; }; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 03a5e1e4d7..81e86412d4 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4916,6 +4916,24 @@ qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, if (VIR_STRDUP(cpu->name, tmp) < 0) goto cleanup; + + if (virJSONValueObjectHasKey(child, "unavailable-features")) { + virJSONValuePtr blockers; + + blockers = virJSONValueObjectGetArray(child, + "unavailable-features"); + if (!blockers) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unavailable-features in query-cpu-definitions " + "reply data was not an array")); + goto cleanup; + } + + if (virJSONValueArraySize(blockers) > 0) + cpu->usable = VIR_TRISTATE_BOOL_NO; + else + cpu->usable = VIR_TRISTATE_BOOL_YES; + } } ret = n; diff --git a/tests/domaincapsschemadata/qemu_2.8.0-tcg.x86_64.xml b/tests/domaincapsschemadata/qemu_2.8.0-tcg.x86_64.xml index fe598e98b3..dd9285311c 100644 --- a/tests/domaincapsschemadata/qemu_2.8.0-tcg.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.8.0-tcg.x86_64.xml @@ -24,35 +24,35 @@ Broadwell - qemu64 - qemu32 - phenom - pentium3 - pentium2 - pentium - n270 - kvm64 - kvm32 - coreduo - core2duo - athlon - Westmere - Skylake-Client - SandyBridge - Penryn - Opteron_G5 - Opteron_G4 - Opteron_G3 - Opteron_G2 - Opteron_G1 - Nehalem - IvyBridge - Haswell - Haswell-noTSX - Conroe - Broadwell - Broadwell-noTSX - 486 + qemu64 + qemu32 + phenom + pentium3 + pentium2 + pentium + n270 + kvm64 + kvm32 + coreduo + core2duo + athlon + Westmere + Skylake-Client + SandyBridge + Penryn + Opteron_G5 + Opteron_G4 + Opteron_G3 + Opteron_G2 + Opteron_G1 + Nehalem + IvyBridge + Haswell + Haswell-noTSX + Conroe + Broadwell + Broadwell-noTSX + 486 diff --git a/tests/domaincapsschemadata/qemu_2.8.0.x86_64.xml b/tests/domaincapsschemadata/qemu_2.8.0.x86_64.xml index 7b8f90ee32..4c5fffcad4 100644 --- a/tests/domaincapsschemadata/qemu_2.8.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.8.0.x86_64.xml @@ -24,35 +24,35 @@ Broadwell - qemu64 - qemu32 - phenom - pentium3 - pentium2 - pentium - n270 - kvm64 - kvm32 - coreduo - core2duo - athlon - Westmere - Skylake-Client - SandyBridge - Penryn - Opteron_G5 - Opteron_G4 - Opteron_G3 - Opteron_G2 - Opteron_G1 - Nehalem - IvyBridge - Haswell - Haswell-noTSX - Conroe - Broadwell - Broadwell-noTSX - 486 + qemu64 + qemu32 + phenom + pentium3 + pentium2 + pentium + n270 + kvm64 + kvm32 + coreduo + core2duo + athlon + Westmere + Skylake-Client + SandyBridge + Penryn + Opteron_G5 + Opteron_G4 + Opteron_G3 + Opteron_G2 + Opteron_G1 + Nehalem + IvyBridge + Haswell + Haswell-noTSX + Conroe + Broadwell + Broadwell-noTSX + 486 diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml index 7113269bf5..e487c40509 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml @@ -200,66 +200,66 @@ 0 (v2.8.0-rc1-dirty) x86_64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index f729b2eda0..ff88d1f87f 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -432,10 +432,12 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) " \"name\": \"qemu64\" " " }, " " { " - " \"name\": \"Opteron_G4\" " + " \"name\": \"Opteron_G4\", " + " \"unavailable-features\": [\"vme\"]" " }, " " { " - " \"name\": \"Westmere\" " + " \"name\": \"Westmere\", " + " \"unavailable-features\": []" " } " " ]" "}") < 0) @@ -451,7 +453,7 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) goto cleanup; } -#define CHECK(i, wantname) \ +#define CHECK_FULL(i, wantname, Usable) \ do { \ if (STRNEQ(cpus[i]->name, (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ @@ -459,13 +461,28 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) cpus[i]->name, (wantname)); \ goto cleanup; \ } \ + if (cpus[i]->usable != (Usable)) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "%s: expecting usable flag %d, got %d", \ + cpus[i]->name, Usable, cpus[i]->usable); \ + goto cleanup; \ + } \ } while (0) +#define CHECK(i, wantname) \ + CHECK_FULL(i, wantname, VIR_TRISTATE_BOOL_ABSENT) + +#define CHECK_USABLE(i, wantname, usable) \ + CHECK_FULL(i, wantname, \ + usable ? VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO) + CHECK(0, "qemu64"); - CHECK(1, "Opteron_G4"); - CHECK(2, "Westmere"); + CHECK_USABLE(1, "Opteron_G4", false); + CHECK_USABLE(2, "Westmere", true); #undef CHECK +#undef CHECK_USABLE +#undef CHECK_FULL ret = 0; diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 8f37ee5375..8d1bdb7103 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -303,31 +303,39 @@ testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) if (ARCH_IS_X86(arch)) { if (virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_KVM, x86Models, - ARRAY_CARDINALITY(x86Models)) < 0 || + ARRAY_CARDINALITY(x86Models), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_QEMU, x86Models, - ARRAY_CARDINALITY(x86Models)) < 0) + ARRAY_CARDINALITY(x86Models), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) return -1; if (!skipLegacy) { if (virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_KVM, x86LegacyModels, - ARRAY_CARDINALITY(x86LegacyModels)) < 0 || + ARRAY_CARDINALITY(x86LegacyModels), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_QEMU, x86LegacyModels, - ARRAY_CARDINALITY(x86LegacyModels)) < 0) + ARRAY_CARDINALITY(x86LegacyModels), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) return -1; } } else if (ARCH_IS_ARM(arch)) { if (virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_KVM, armModels, - ARRAY_CARDINALITY(armModels)) < 0 || + ARRAY_CARDINALITY(armModels), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_QEMU, armModels, - ARRAY_CARDINALITY(armModels)) < 0) + ARRAY_CARDINALITY(armModels), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) return -1; } else if (ARCH_IS_PPC64(arch)) { if (virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_KVM, ppc64Models, - ARRAY_CARDINALITY(ppc64Models)) < 0 || + ARRAY_CARDINALITY(ppc64Models), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || virQEMUCapsAddCPUDefinitions(caps, VIR_DOMAIN_VIRT_QEMU, ppc64Models, - ARRAY_CARDINALITY(ppc64Models)) < 0) + ARRAY_CARDINALITY(ppc64Models), + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) return -1; } -- 2.39.5