[libvirt] [PATCH 4/5] qemu-caps: Get host model directly from Qemu when available

Jiri Denemark jdenemar at redhat.com
Thu Nov 3 10:49:20 UTC 2016


On Wed, Nov 02, 2016 at 16:34:34 -0400, Jason J. Herne wrote:
> From: "Collin L. Walling" <walling at 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 at linux.vnet.ibm.com>
> Signed-off-by: Jason J. Herne <jjherne at 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




More information about the libvir-list mailing list