On Wed, Nov 02, 2016 at 16:34:34 -0400, Jason J. Herne wrote:
From: "Collin L. Walling"
<walling(a)linux.vnet.ibm.com>
When qmp query-cpu-model-expansion is available probe Qemu for its view of the
host model. In kvm environments this can provide a more complete view of the
host model because features supported by Qemu and Kvm can be considered.
Signed-off-by: Collin L. Walling <walling(a)linux.vnet.ibm.com>
Signed-off-by: Jason J. Herne <jjherne(a)linux.vnet.ibm.com>
---
src/qemu/qemu_capabilities.c | 88 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 7a8202a..4a6ae07 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -389,6 +389,8 @@ struct _virQEMUCaps {
size_t ngicCapabilities;
virGICCapability *gicCapabilities;
+ virCPUDefPtr hostCPUModelFromQemu;
+
Heh, why? We already have virCPUDefPtr hostCPUModel in this struct and
it was added exactly for the purpose of storing the host CPU model as
probed from QEMU. Only if probing QEMU cannot be used (which is the
current state), we copy the host CPU from virCaps.
/* Anything below is not stored in the cache since the values
are
* re-computed from the other fields or external data sources every
* time we probe QEMU or load the results from the cache.
@@ -2118,6 +2120,10 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
!(ret->hostCPUModel = virCPUDefCopy(qemuCaps->hostCPUModel)))
goto error;
+ if (qemuCaps->hostCPUModelFromQemu &&
+ !(ret->hostCPUModelFromQemu =
virCPUDefCopy(qemuCaps->hostCPUModelFromQemu)))
+ goto error;
+
if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0)
goto error;
ret->nmachineTypes = qemuCaps->nmachineTypes;
@@ -2728,6 +2734,51 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps,
return ret;
}
+static int
+virQEMUCapsProbeQMPCPUModelExpansion(virQEMUCapsPtr qemuCaps,
+ qemuMonitorPtr mon)
+{
+ qemuMonitorCPUModelInfoPtr model_info;
+ virCPUDefPtr hostcpumodel;
+ int nfeatures;
+ int ret = -1;
+ size_t i;
+
+ if (qemuMonitorGetCPUModelExpansion(mon, "static", "host",
&model_info) < 0)
+ goto cleanup;
+
+ if (model_info == NULL) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(hostcpumodel) < 0)
+ goto cleanup;
+
+ if (VIR_STRDUP(hostcpumodel->model, model_info->name) < 0)
+ goto cleanup;
+
+ nfeatures = hostcpumodel->nfeatures = model_info->nprops;
+
+ if (VIR_ALLOC_N(hostcpumodel->features, nfeatures) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nfeatures; i++) {
+ if (VIR_STRDUP(hostcpumodel->features[i].name, model_info->props[i].name)
< 0)
+ goto cleanup;
+
+ hostcpumodel->features[i].policy = -1;
+ }
+
+ hostcpumodel->arch = qemuCaps->arch;
+ qemuCaps->hostCPUModelFromQemu = virCPUDefCopy(hostcpumodel);
+ ret = 0;
+
+ cleanup:
+ virCPUDefFree(hostcpumodel);
+ return ret;
+}
The virQEMUCapsProbeQMPCPUModelExpansion (although I'd call it
virQEMUCapsProbeQMPHostCPU) should just call
qemuMonitorGetCPUModelExpansion and store the result in qemuCaps so that
it can be stored in the capabilities cache. The rest of the code which
takes the raw data from QEMU and creates host CPU model definition from
it should go into virQEMUCapsInitHostCPUModel.
+
struct tpmTypeToCaps {
int type;
virQEMUCapsFlags caps;
@@ -2958,6 +3009,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
virCapsPtr caps)
{
virCPUDefPtr cpu = NULL;
+ virCPUDefPtr src = NULL;
if (!caps)
return;
@@ -2974,7 +3026,10 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
cpu->mode = VIR_CPU_MODE_CUSTOM;
cpu->match = VIR_CPU_MATCH_EXACT;
- if (virCPUDefCopyModelFilter(cpu, caps->host.cpu, true,
+ if (!(src = qemuCaps->hostCPUModelFromQemu))
+ src = caps->host.cpu;
+
+ if (virCPUDefCopyModelFilter(cpu, src, true,
virQEMUCapsCPUFilterFeatures, NULL) < 0)
goto error;
}
@@ -3118,6 +3173,21 @@ virQEMUCapsLoadCache(virCapsPtr caps,
}
VIR_FREE(str);
+ xmlNodePtr node;
+ if ((node = virXPathNode("./host/cpu[1]", ctxt))) {
+ xmlNodePtr oldNode = ctxt->node;
+ ctxt->node = node;
+ if (!(qemuCaps->hostCPUModelFromQemu = virCPUDefParseXML(node,
+ ctxt,
+ VIR_CPU_TYPE_HOST))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing host cpu data in QEMU capabilities
cache"));
+ goto cleanup;
+ }
+ ctxt->node = oldNode;
+ node = NULL;
+ }
+
As I said above, it's the reply from QEMU (qemuMonitorCPUModelInfoPtr)
that should be loaded from the cache.
if ((n = virXPathNodeSet("./cpu", ctxt, &nodes))
< 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to parse qemu capabilities cpus"));
@@ -3298,6 +3368,20 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps,
virBufferAsprintf(&buf, "<arch>%s</arch>\n",
virArchToString(qemuCaps->arch));
+ if (qemuCaps->hostCPUModelFromQemu) {
+ virBufferAddLit(&buf, "<host>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAddLit(&buf, "<cpu>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferEscapeString(&buf, "<arch>%s</arch>\n",
+
virArchToString(qemuCaps->hostCPUModelFromQemu->arch));
+ virCPUDefFormatBuf(&buf, qemuCaps->hostCPUModelFromQemu, true);
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</cpu>\n");
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</host>\n");
+ }
+
And qemuMonitorCPUModelInfoPtr should be stored in the cache.
if (qemuCaps->cpuDefinitions) {
for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) {
virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i;
@@ -3790,6 +3874,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
goto cleanup;
if (virQEMUCapsProbeQMPCPUDefinitions(qemuCaps, mon) < 0)
goto cleanup;
+ if (virQEMUCapsProbeQMPCPUModelExpansion(qemuCaps, mon) < 0)
+ goto cleanup;
if (virQEMUCapsProbeQMPKVMState(qemuCaps, mon) < 0)
goto cleanup;
if (virQEMUCapsProbeQMPTPM(qemuCaps, mon) < 0)
Jirka