On 4/26/19 5:22 PM, walling(a)linux.ibm.com wrote:
From: Collin Walling <walling(a)linux.ibm.com>
This command is hooked into the virsh hypervisor-cpu-baseline command.
As such, the CPU models provided in the XML sent to the command will be
baselined with the CPU contained in the QEMU capabilities file for the
appropriate QEMU binary (for s390x, this CPU definition can be observed
via virsh domcapabilities).
Signed-off-by: Collin Walling <walling(a)linux.ibm.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/qemu/qemu_capabilities.c | 102 +++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_capabilities.h | 7 +++
src/qemu/qemu_driver.c | 28 ++++++++++++
3 files changed, 137 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 0835f65..e3f3d0b 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -5402,3 +5402,105 @@ virQEMUCapsStripMachineAliases(virQEMUCapsPtr qemuCaps)
for (i = 0; i < qemuCaps->nmachineTypes; i++)
VIR_FREE(qemuCaps->machineTypes[i].alias);
}
+
+
+static void
+virQEMUCapsFixFeatPolicy(virCPUDefPtr cpu)
+{
+ size_t i;
+
+ /* Features reported by QMP are either on or off. If the feature is
+ * off, let's set the policy to disabled. Otherwise set it to required.
+ */
+ for (i = 0; i < cpu->nfeatures; i++) {
+ if (cpu->features[i].policy == 0)
+ cpu->features[i].policy = VIR_CPU_FEATURE_DISABLE;
+ else
+ cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
+ }
+}
+
+
+static int
+virQEMUCapsStealCPUModelFromInfo(qemuMonitorCPUModelInfoPtr info,
+ virCPUDefPtr cpu)
+{
+ size_t i;
+
+ virCPUDefFreeModel(cpu);
+
+ VIR_STEAL_PTR(cpu->model, info->name);
+
+ for (i = 0; i < info->nprops; i++) {
+ char *name = info->props[i].name;
+ int policy = 0;
+
+ /* If monitor prop type is boolean and is true, force the feat on */
+ if (info->props[i].type == QEMU_MONITOR_CPU_PROPERTY_BOOLEAN)
+ policy = info->props[i].value.boolean;
+
+ if (virCPUDefAddFeature(cpu, name, policy) < 0)
+ goto error;
+ }
+
+ qemuMonitorCPUModelInfoFree(info);
+ return 0;
+
+ error:
+ virCPUDefFree(cpu);
+ return -1;
+}
+
+
+virCPUDefPtr
+virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps,
+ const char *libDir,
+ uid_t runUid,
+ gid_t runGid,
+ int ncpus,
+ virCPUDefPtr *cpus)
+{
+ qemuMonitorCPUModelInfoPtr result = NULL;
+ qemuProcessQMPPtr proc = NULL;
+ virCPUDefPtr cpu = NULL;
+ virCPUDefPtr baseline = NULL;
+ size_t i;
+
+ if (VIR_ALLOC(cpu) < 0)
+ goto cleanup;
+
+ if (virCPUDefCopyModel(cpu, cpus[0], false))
+ goto cleanup;
+
+ if (!(proc = qemuProcessQMPNew(qemuCaps->binary, libDir,
+ runUid, runGid, false)))
+ goto cleanup;
+
+ if (qemuProcessQMPStart(proc) < 0)
+ goto cleanup;
+
+ for (i = 1; i < ncpus; i++) {
+ if (qemuMonitorGetCPUModelBaseline(proc->mon, cpu->model,
+ cpu->nfeatures, cpu->features,
+ cpus[i]->model, cpus[i]->nfeatures,
+ cpus[i]->features, &result) < 0)
+ goto cleanup;
+
+ if (virQEMUCapsStealCPUModelFromInfo(result, cpu) < 0)
+ goto cleanup;
+
+ result = NULL;
+ }
+
+ virQEMUCapsFixFeatPolicy(cpu);
+ VIR_STEAL_PTR(baseline, cpu);
+
+ cleanup:
+ if (!baseline)
+ virQEMUCapsLogProbeFailure(qemuCaps->binary);
+
+ qemuMonitorCPUModelInfoFree(result);
+ qemuProcessQMPFree(proc);
+ virCPUDefFree(cpu);
+ return baseline;
+}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 102f259..08fd555 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -648,4 +648,11 @@ virQEMUCapsGetSEVCapabilities(virQEMUCapsPtr qemuCaps);
virArch virQEMUCapsArchFromString(const char *arch);
const char *virQEMUCapsArchToString(virArch arch);
+virCPUDefPtr virQEMUCapsCPUModelBaseline(virQEMUCapsPtr qemuCaps,
+ const char *libDir,
+ uid_t runUid,
+ gid_t runGid,
+ int ncpus,
+ virCPUDefPtr *cpus);
+
#endif /* LIBVIRT_QEMU_CAPABILITIES_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f48d925..e1e1fea 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13576,6 +13576,7 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn,
unsigned int flags)
{
virQEMUDriverPtr driver = conn->privateData;
+ virQEMUDriverConfigPtr config = driver->config;
virCPUDefPtr *cpus = NULL;
virQEMUCapsPtr qemuCaps = NULL;
virArch arch;
@@ -13630,6 +13631,33 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn,
if (!(cpu = virCPUBaseline(arch, cpus, ncpus, cpuModels,
(const char **)features, migratable)))
goto cleanup;
+ } else if (ARCH_IS_S390(arch) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_BASELINE)) {
+ /* Add the hypervisor CPU to the list */
+ virCPUDefPtr hvCPU;
+ size_t alloc = ncpus + 1;
+
+ if (VIR_RESIZE_N(cpus, alloc, ncpus, 1) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(cpus[ncpus]) < 0)
+ goto cleanup;
+
+ hvCPU = virQEMUCapsGetHostModel(qemuCaps, virttype,
+ VIR_QEMU_CAPS_HOST_CPU_REPORTED);
+
+ if (virCPUDefCopyModel(cpus[ncpus], hvCPU, false) < 0)
+ goto cleanup;
+
+ ncpus++;
+
+ if (!(cpu = virQEMUCapsCPUModelBaseline(qemuCaps, config->libDir,
+ config->user, config->group,
+ ncpus, cpus)))
+ goto cleanup;
+
+ if (!(flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES))
+ virCPUDefFreeFeatures(cpu);
} else {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("computing baseline hypervisor CPU is not supported
"