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

Jiri Denemark jdenemar at redhat.com
Fri Jan 6 11:51:41 UTC 2017


On Sun, Dec 18, 2016 at 14:22:27 -0500, Jason J. Herne wrote:
> 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>
> 
> # Conflicts:
> #	tests/qemucapabilitiesdata/caps_2.8.0.s390x.replies
> 
> Signed-off-by: Jason J. Herne <jjherne at linux.vnet.ibm.com>
> ---
>  src/qemu/qemu_capabilities.c                       | 185 ++++++++++++++++++++-
>  tests/domaincapsschemadata/qemu_2.7.0.s390x.xml    |   4 +-
>  tests/domaincapsschemadata/qemu_2.8.0.s390x.xml    |  17 +-
>  .../qemucapabilitiesdata/caps_2.8.0.s390x.replies  |  26 +++
>  tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml    |  17 ++
>  5 files changed, 239 insertions(+), 10 deletions(-)
> 
> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index bff30ed..7d33b19 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
...
> @@ -3055,6 +3117,98 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
>      virResetLastError();
>  }
>  

One more empty line here, please.

> +void
> +virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
> +                            virCapsPtr caps)
> +{
> +    if (!caps || !virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
> +        return;
> +
> +    switch (qemuCaps->arch) {
> +    case VIR_ARCH_S390:
> +    case VIR_ARCH_S390X:
> +        virQEMUCapsCopyCPUModelFromQEMU(qemuCaps);
> +        break;
> +    default: virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);

       default:
           virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);

> +    }
> +}
> +
> +
> +static int
> +virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
> +                                xmlXPathContextPtr ctxt)
> +{
> +    char *str = NULL;
> +    xmlNodePtr hostCPUNode;
> +    xmlNodePtr *featureNodes = NULL;
> +    xmlNodePtr oldnode = ctxt->node;
> +    qemuMonitorCPUModelInfoPtr hostCPU = NULL;
> +    int ret = -1;
> +    size_t i;
> +    int n;
> +
> +    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) {
> +        ret = 0;
> +        goto cleanup;
> +    }

This is not really necessary, properly checking for <hostCPU> element is
enough.

> +
> +    if (!(hostCPUNode = virXPathNode("./hostCPU", ctxt)) ||
> +        VIR_ALLOC(hostCPU) < 0)
> +        goto cleanup;

When QEMU is probed in TCG mode, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION
might be set but ./hostCPU will not be present in the capabilities XML.
The code should not fail in such a case. In other words:

    if (!(hostCPUNode = virXPathNode("./hostCPU", ctxt))) {
        ret = 0;
        goto cleanup;
    }

    if (VIR_ALLOC(hostCPU) < 0)
        goto cleanup;

> +
> +    if ((str = virXMLPropString(hostCPUNode, "model"))) {

Don't confuse virXMLPropString and virXPathString. The latter does not
make a copy of the string while the former does make the copy.

> +        if (VIR_STRDUP(hostCPU->name, str) < 0)
> +            goto cleanup;
> +    }

Anyway, it looks like the name attribute should always be present, so

    if (!(hostCPU->name = virXMLPropString(hostCPUNode, "model"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing host CPU model name in QEMU "
                         "capabilities cache"));
        goto cleanup;
    }

should be enough.

> +
> +    ctxt->node = hostCPUNode;
> +
> +    if ((n = virXPathNodeSet("./feature", ctxt, &featureNodes)) > 0) {
> +        if (VIR_ALLOC_N(hostCPU->props, n) < 0)
> +            goto cleanup;
> +
> +        hostCPU->nprops = n;
> +
> +        for (i = 0; i < n; i++) {
> +            if (!(str = virXMLPropString(featureNodes[i], "name"))) {

You can directly assign it to hostCPU->props[i].name.

> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("missing 'name' element for a host CPU model"

'name' is not an element, it's an attribute.

> +                                 " feature in QEMU capabilities cache"));
> +                goto cleanup;
> +            }
> +            if (VIR_STRDUP(hostCPU->props[i].name, str) < 0)
> +                goto cleanup;

Let's separate the two attributes by an empty line here.

> +            if (!(str = virXMLPropString(featureNodes[i], "supported"))) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("missing 'supported' element for a host CPU"

s/element/attribute/

> +                                 " model feature in QEMU capabilities cache"));
> +                goto cleanup;
> +            }
> +            if (STREQ(str, "yes")) {
> +                hostCPU->props[i].supported = true;
> +            } else if (STREQ(str, "no")) {
> +                hostCPU->props[i].supported = false;
> +            } else {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("malformed supported value: expected 'yes'"
> +                                 " or 'no'"));

It's an internal XML, not something a user is supposed to create so
printing the incorrect value should be enough:

    ..., _("invalid supported value: '%s'"), str);

> +                goto cleanup;
> +            }

You'd leak str here if n > 1.

> +        }
> +    }
> +
> +    qemuCaps->hostCPUModelInfo = hostCPU;
> +    hostCPU = NULL;
> +    ret = 0;
> +
> + cleanup:
> +    ctxt->node = oldnode;
> +    VIR_FREE(str);
> +    VIR_FREE(featureNodes);
> +    qemuMonitorCPUModelInfoFree(hostCPU);
> +    return ret;
> +}
> +
>  
>  static int
>  virQEMUCapsLoadCPUModels(virQEMUCapsPtr qemuCaps,
...
> diff --git a/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml b/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
> index 9f181d3..999e279 100644
> --- a/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
> +++ b/tests/domaincapsschemadata/qemu_2.7.0.s390x.xml
> @@ -20,9 +20,7 @@
>    </os>
>    <cpu>
>      <mode name='host-passthrough' supported='yes'/>
> -    <mode name='host-model' supported='yes'>
> -      <model fallback='allow'></model>
> -    </mode>
> +    <mode name='host-model' supported='no'/>
>      <mode name='custom' supported='no'/>
>    </cpu>
>    <devices>

This hunk should be part of 4/9.

ACK with the attached diff squashed in...

Jirka

diff --git i/src/qemu/qemu_capabilities.c w/src/qemu/qemu_capabilities.c
index a3f97d209..2512e4838 100644
--- i/src/qemu/qemu_capabilities.c
+++ w/src/qemu/qemu_capabilities.c
@@ -3117,6 +3117,7 @@ virQEMUCapsCopyCPUModelFromHost(virQEMUCapsPtr qemuCaps,
     virResetLastError();
 }
 
+
 void
 virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
                             virCapsPtr caps)
@@ -3129,7 +3130,9 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
     case VIR_ARCH_S390X:
         virQEMUCapsCopyCPUModelFromQEMU(qemuCaps);
         break;
-    default: virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);
+
+    default:
+        virQEMUCapsCopyCPUModelFromHost(qemuCaps, caps);
     }
 }
 
@@ -3147,18 +3150,19 @@ virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
     size_t i;
     int n;
 
-    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) {
+    if (!(hostCPUNode = virXPathNode("./hostCPU", ctxt))) {
         ret = 0;
         goto cleanup;
     }
 
-    if (!(hostCPUNode = virXPathNode("./hostCPU", ctxt)) ||
-        VIR_ALLOC(hostCPU) < 0)
+    if (VIR_ALLOC(hostCPU) < 0)
         goto cleanup;
 
-    if ((str = virXMLPropString(hostCPUNode, "model"))) {
-        if (VIR_STRDUP(hostCPU->name, str) < 0)
-            goto cleanup;
+    if (!(hostCPU->name = virXMLPropString(hostCPUNode, "model"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("missing host CPU model name in QEMU "
+                         "capabilities cache"));
+        goto cleanup;
     }
 
     ctxt->node = hostCPUNode;
@@ -3170,17 +3174,17 @@ virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
         hostCPU->nprops = n;
 
         for (i = 0; i < n; i++) {
-            if (!(str = virXMLPropString(featureNodes[i], "name"))) {
+            hostCPU->props[i].name = virXMLPropString(featureNodes[i], "name");
+            if (!hostCPU->props[i].name) {
                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("missing 'name' element for a host CPU model"
-                                 " feature in QEMU capabilities cache"));
+                               _("missing 'name' attribute for a host CPU"
+                                 " model feature in QEMU capabilities cache"));
                 goto cleanup;
             }
-            if (VIR_STRDUP(hostCPU->props[i].name, str) < 0)
-                goto cleanup;
+
             if (!(str = virXMLPropString(featureNodes[i], "supported"))) {
                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("missing 'supported' element for a host CPU"
+                               _("missing 'supported' attribute for a host CPU"
                                  " model feature in QEMU capabilities cache"));
                 goto cleanup;
             }
@@ -3189,11 +3193,11 @@ virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps,
             } else if (STREQ(str, "no")) {
                 hostCPU->props[i].supported = false;
             } else {
-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("malformed supported value: expected 'yes'"
-                                 " or 'no'"));
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("invalid supported value: '%s'"), str);
                 goto cleanup;
             }
+            VIR_FREE(str);
         }
     }
 




More information about the libvir-list mailing list