[libvirt] [PATCH 21/24] qemu: Introduce generic qemuMonitorGetGuestCPU

Jiri Denemark posted 24 patches 6 years, 7 months ago
There is a newer version of this series
[libvirt] [PATCH 21/24] qemu: Introduce generic qemuMonitorGetGuestCPU
Posted by Jiri Denemark 6 years, 7 months ago
Unlike the old version (which is now called qemuMonitorGetGuestCPUx86),
this monitor API checks for individual features by their names rather
than processing CPUID bits. Thus we can get the list of enabled and
disabled features for both CPUID and MSR features.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_monitor.c      |  36 ++++++
 src/qemu/qemu_monitor.h      |  10 ++
 src/qemu/qemu_monitor_json.c | 211 +++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h |   7 ++
 4 files changed, 264 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 344aac09f0..99aadba2e2 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4107,6 +4107,42 @@ qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
 }
 
 
+/**
+ * qemuMonitorGetGuestCPU:
+ * @mon: Pointer to the monitor
+ * @arch: CPU architecture
+ * @translate: callback for translating CPU feature names from QEMU to libvirt
+ * @opaque: data for @translate callback
+ * @enabled: returns the CPU data for all enabled features
+ * @disabled: returns the CPU data for features which we asked for
+ *      (either explicitly or via a named CPU model) but QEMU disabled them
+ *
+ * Retrieve the definition of the guest CPU from a running QEMU instance.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
+                       virArch arch,
+                       qemuMonitorCPUFeatureTranslationCallback translate,
+                       void *opaque,
+                       virCPUDataPtr *enabled,
+                       virCPUDataPtr *disabled)
+{
+    VIR_DEBUG("arch=%s translate=%p opaque=%p enabled=%p disabled=%p",
+              virArchToString(arch), translate, opaque, enabled, disabled);
+
+    QEMU_CHECK_MONITOR(mon);
+
+    *enabled = NULL;
+    if (disabled)
+        *disabled = NULL;
+
+    return qemuMonitorJSONGetGuestCPU(mon, arch, translate, opaque,
+                                      enabled, disabled);
+}
+
+
 /**
  * qemuMonitorRTCResetReinjection:
  * @mon: Pointer to the monitor
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index ac2499c22a..f5be74f461 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1154,6 +1154,16 @@ int qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
                               virCPUDataPtr *data,
                               virCPUDataPtr *disabled);
 
+typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(const char *name,
+                                                                void *opaque);
+
+int qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
+                           virArch arch,
+                           qemuMonitorCPUFeatureTranslationCallback translate,
+                           void *opaque,
+                           virCPUDataPtr *enabled,
+                           virCPUDataPtr *disabled);
+
 int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon);
 
 typedef struct _qemuMonitorIOThreadInfo qemuMonitorIOThreadInfo;
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index efcef211ed..1662e47301 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6137,6 +6137,64 @@ int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
 }
 
 
+static int
+qemuMonitorJSONGetStringListProperty(qemuMonitorPtr mon,
+                                     const char *path,
+                                     const char *property,
+                                     char ***strList)
+{
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr data;
+    char **list = NULL;
+    size_t n;
+    size_t i;
+    int ret = -1;
+
+    *strList = NULL;
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
+                                           "s:path", path,
+                                           "s:property", property,
+                                           NULL)))
+        return -1;
+
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+        goto cleanup;
+
+    if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
+        goto cleanup;
+
+    data = virJSONValueObjectGetArray(reply, "return");
+    n = virJSONValueArraySize(data);
+
+    if (VIR_ALLOC_N(list, n + 1) < 0)
+        goto cleanup;
+
+    for (i = 0; i < n; i++) {
+        virJSONValuePtr item = virJSONValueArrayGet(data, i);
+
+        if (virJSONValueGetType(item) != VIR_JSON_TYPE_STRING) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unexpected value in %s array"), property);
+            goto cleanup;
+        }
+
+        if (VIR_STRDUP(list[i], virJSONValueGetString(item)) < 0)
+            goto cleanup;
+    }
+
+    VIR_STEAL_PTR(*strList, list);
+    ret = n;
+
+ cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    virStringListFree(list);
+    return ret;
+}
+
+
 #define MAKE_SET_CMD(STRING, VALUE) \
     cmd = qemuMonitorJSONMakeCommand("qom-set", \
                                       "s:path", path, \
@@ -7369,6 +7427,159 @@ qemuMonitorJSONGetGuestCPUx86(qemuMonitorPtr mon,
     return -1;
 }
 
+
+static int
+qemuMonitorJSONGetCPUProperties(qemuMonitorPtr mon,
+                                char ***props)
+{
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    int ret = -1;
+
+    *props = NULL;
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
+                                           "s:path", QOM_CPU_PATH,
+                                           NULL)))
+        return -1;
+
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+        goto cleanup;
+
+    if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
+        ret = 0;
+        goto cleanup;
+    }
+
+    ret = qemuMonitorJSONParsePropsList(cmd, reply, "bool", props);
+
+ cleanup:
+    virJSONValueFree(reply);
+    virJSONValueFree(cmd);
+    return ret;
+}
+
+
+static int
+qemuMonitorJSONGetCPUData(qemuMonitorPtr mon,
+                          qemuMonitorCPUFeatureTranslationCallback translate,
+                          void *opaque,
+                          virCPUDataPtr data)
+{
+    qemuMonitorJSONObjectProperty prop = { .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN };
+    char **props;
+    char **p;
+    int ret = -1;
+
+    if (qemuMonitorJSONGetCPUProperties(mon, &props) < 0)
+        goto cleanup;
+
+    for (p = props; p && *p; p++) {
+        const char *name = *p;
+
+        if (qemuMonitorJSONGetObjectProperty(mon, QOM_CPU_PATH, name, &prop) < 0)
+            goto cleanup;
+
+        if (!prop.val.b)
+            continue;
+
+        if (translate)
+            name = translate(name, opaque);
+
+        if (virCPUDataAddFeature(data, name) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virStringListFree(props);
+    return ret;
+}
+
+
+static int
+qemuMonitorJSONGetCPUDataDisabled(qemuMonitorPtr mon,
+                                  qemuMonitorCPUFeatureTranslationCallback translate,
+                                  void *opaque,
+                                  virCPUDataPtr data)
+{
+    char **props;
+    char **p;
+    int ret = -1;
+
+    if (qemuMonitorJSONGetStringListProperty(mon, QOM_CPU_PATH,
+                                             "unavailable-features", &props) < 0)
+        goto cleanup;
+
+    for (p = props; p && *p; p++) {
+        const char *name = *p;
+
+        if (translate)
+            name = translate(name, opaque);
+
+        if (virCPUDataAddFeature(data, name) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virStringListFree(props);
+    return ret;
+}
+
+
+/**
+ * qemuMonitorJSONGetGuestCPU:
+ * @mon: Pointer to the monitor
+ * @arch: CPU architecture
+ * @translate: callback for translating CPU feature names from QEMU to libvirt
+ * @opaque: data for @translate callback
+ * @enabled: returns the CPU data for all enabled features
+ * @disabled: returns the CPU data for features which we asked for
+ *      (either explicitly or via a named CPU model) but QEMU disabled them
+ *
+ * Retrieve the definition of the guest CPU from a running QEMU instance.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
+                           virArch arch,
+                           qemuMonitorCPUFeatureTranslationCallback translate,
+                           void *opaque,
+                           virCPUDataPtr *enabled,
+                           virCPUDataPtr *disabled)
+{
+    virCPUDataPtr cpuEnabled = NULL;
+    virCPUDataPtr cpuDisabled = NULL;
+    int ret = -1;
+
+    if (!(cpuEnabled = virCPUDataNew(arch)) ||
+        !(cpuDisabled = virCPUDataNew(arch)))
+        goto cleanup;
+
+    if (qemuMonitorJSONGetCPUData(mon, translate, opaque, cpuEnabled) < 0)
+        goto cleanup;
+
+    if (disabled &&
+        qemuMonitorJSONGetCPUDataDisabled(mon, translate, opaque, cpuDisabled) < 0)
+        goto cleanup;
+
+    VIR_STEAL_PTR(*enabled, cpuEnabled);
+    if (disabled)
+        VIR_STEAL_PTR(*disabled, cpuDisabled);
+
+    ret = 0;
+
+ cleanup:
+    virCPUDataFree(cpuEnabled);
+    virCPUDataFree(cpuDisabled);
+    return ret;
+}
+
+
 int
 qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon)
 {
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 424861b531..a874c9c01c 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -493,6 +493,13 @@ int qemuMonitorJSONGetGuestCPUx86(qemuMonitorPtr mon,
                                   virCPUDataPtr *data,
                                   virCPUDataPtr *disabled);
 
+int qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
+                               virArch arch,
+                               qemuMonitorCPUFeatureTranslationCallback translate,
+                               void *opaque,
+                               virCPUDataPtr *enabled,
+                               virCPUDataPtr *disabled);
+
 int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon);
 
 int qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon,
-- 
2.22.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 21/24] qemu: Introduce generic qemuMonitorGetGuestCPU
Posted by Ján Tomko 6 years, 7 months ago
On Wed, Jun 19, 2019 at 11:38:18AM +0200, Jiri Denemark wrote:
>Unlike the old version (which is now called qemuMonitorGetGuestCPUx86),
>this monitor API checks for individual features by their names rather
>than processing CPUID bits. Thus we can get the list of enabled and
>disabled features for both CPUID and MSR features.
>
>Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
>---
> src/qemu/qemu_monitor.c      |  36 ++++++
> src/qemu/qemu_monitor.h      |  10 ++
> src/qemu/qemu_monitor_json.c | 211 +++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor_json.h |   7 ++
> 4 files changed, 264 insertions(+)
>
>diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>index 344aac09f0..99aadba2e2 100644
>--- a/src/qemu/qemu_monitor.c
>+++ b/src/qemu/qemu_monitor.c
>@@ -4107,6 +4107,42 @@ qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
> }
>
>
>+/**
>+ * qemuMonitorGetGuestCPU:
>+ * @mon: Pointer to the monitor
>+ * @arch: CPU architecture
>+ * @translate: callback for translating CPU feature names from QEMU to libvirt
>+ * @opaque: data for @translate callback
>+ * @enabled: returns the CPU data for all enabled features
>+ * @disabled: returns the CPU data for features which we asked for
>+ *      (either explicitly or via a named CPU model) but QEMU disabled them
>+ *
>+ * Retrieve the definition of the guest CPU from a running QEMU instance.
>+ *
>+ * Returns 0 on success, -1 on error.
>+ */
>+int
>+qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
>+                       virArch arch,
>+                       qemuMonitorCPUFeatureTranslationCallback translate,
>+                       void *opaque,
>+                       virCPUDataPtr *enabled,
>+                       virCPUDataPtr *disabled)
>+{
>+    VIR_DEBUG("arch=%s translate=%p opaque=%p enabled=%p disabled=%p",
>+              virArchToString(arch), translate, opaque, enabled, disabled);
>+
>+    QEMU_CHECK_MONITOR(mon);
>+
>+    *enabled = NULL;
>+    if (disabled)
>+        *disabled = NULL;
>+
>+    return qemuMonitorJSONGetGuestCPU(mon, arch, translate, opaque,

Hehe, "monarch".

>+                                      enabled, disabled);
>+}
>+
>+
> /**
>  * qemuMonitorRTCResetReinjection:
>  * @mon: Pointer to the monitor
>diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
>index ac2499c22a..f5be74f461 100644
>--- a/src/qemu/qemu_monitor.h
>+++ b/src/qemu/qemu_monitor.h
>@@ -1154,6 +1154,16 @@ int qemuMonitorGetGuestCPUx86(qemuMonitorPtr mon,
>                               virCPUDataPtr *data,
>                               virCPUDataPtr *disabled);
>
>+typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(const char *name,
>+                                                                void *opaque);
>+
>+int qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
>+                           virArch arch,
>+                           qemuMonitorCPUFeatureTranslationCallback translate,
>+                           void *opaque,
>+                           virCPUDataPtr *enabled,
>+                           virCPUDataPtr *disabled);
>+
> int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon);
>
> typedef struct _qemuMonitorIOThreadInfo qemuMonitorIOThreadInfo;
>diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>index efcef211ed..1662e47301 100644
>--- a/src/qemu/qemu_monitor_json.c
>+++ b/src/qemu/qemu_monitor_json.c
>@@ -6137,6 +6137,64 @@ int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
> }
>
>
>+static int
>+qemuMonitorJSONGetStringListProperty(qemuMonitorPtr mon,
>+                                     const char *path,
>+                                     const char *property,
>+                                     char ***strList)
>+{
>+    virJSONValuePtr cmd;
>+    virJSONValuePtr reply = NULL;

VIR_AUTOPTR(virJSONValue) cmd = NULL;
VIR_AUTOPTR(virJSONValue) reply = NULL;

>+    virJSONValuePtr data;
>+    char **list = NULL;

VIR_AUTOSTRINGLIST list = NULL;

>+    size_t n;
>+    size_t i;
>+    int ret = -1;
>+
>+    *strList = NULL;
>+
>+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
>+                                           "s:path", path,
>+                                           "s:property", property,
>+                                           NULL)))
>+        return -1;
>+
>+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
>+        goto cleanup;
>+
>+    if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
>+        goto cleanup;
>+
>+    data = virJSONValueObjectGetArray(reply, "return");
>+    n = virJSONValueArraySize(data);
>+
>+    if (VIR_ALLOC_N(list, n + 1) < 0)
>+        goto cleanup;
>+
>+    for (i = 0; i < n; i++) {
>+        virJSONValuePtr item = virJSONValueArrayGet(data, i);
>+
>+        if (virJSONValueGetType(item) != VIR_JSON_TYPE_STRING) {
>+            virReportError(VIR_ERR_INTERNAL_ERROR,
>+                           _("unexpected value in %s array"), property);
>+            goto cleanup;
>+        }
>+
>+        if (VIR_STRDUP(list[i], virJSONValueGetString(item)) < 0)
>+            goto cleanup;
>+    }
>+
>+    VIR_STEAL_PTR(*strList, list);
>+    ret = n;
>+
>+ cleanup:
>+    virJSONValueFree(cmd);
>+    virJSONValueFree(reply);
>+    virStringListFree(list);
>+    return ret;
>+}
>+
>+
> #define MAKE_SET_CMD(STRING, VALUE) \
>     cmd = qemuMonitorJSONMakeCommand("qom-set", \
>                                       "s:path", path, \
>@@ -7369,6 +7427,159 @@ qemuMonitorJSONGetGuestCPUx86(qemuMonitorPtr mon,
>     return -1;
> }
>
>+
>+static int
>+qemuMonitorJSONGetCPUProperties(qemuMonitorPtr mon,
>+                                char ***props)
>+{
>+    virJSONValuePtr cmd;
>+    virJSONValuePtr reply = NULL;

VIR_AUTOPTR(virJSONValue) cmd = NULL;
VIR_AUTOPTR(virJSONValue) reply = NULL;

>+    int ret = -1;
>+
>+    *props = NULL;
>+
>+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
>+                                           "s:path", QOM_CPU_PATH,
>+                                           NULL)))
>+        return -1;
>+
>+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
>+        goto cleanup;
>+
>+    if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {

Shouldn't this be a hard error? IIUC this will be called only for QEMUs
which do have the capability.

On the other hand, ignoring a missing device is consistent with other
GetProperties helpers.

>+        ret = 0;
>+        goto cleanup;
>+    }
>+
>+    ret = qemuMonitorJSONParsePropsList(cmd, reply, "bool", props);
>+
>+ cleanup:
>+    virJSONValueFree(reply);
>+    virJSONValueFree(cmd);
>+    return ret;
>+}
>+
>+
>+static int
>+qemuMonitorJSONGetCPUData(qemuMonitorPtr mon,
>+                          qemuMonitorCPUFeatureTranslationCallback translate,
>+                          void *opaque,
>+                          virCPUDataPtr data)
>+{
>+    qemuMonitorJSONObjectProperty prop = { .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN };
>+    char **props;

VIR_AUTOSTRINGLIST props = NULL;

>+    char **p;
>+    int ret = -1;
>+
>+    if (qemuMonitorJSONGetCPUProperties(mon, &props) < 0)
>+        goto cleanup;
>+
>+    for (p = props; p && *p; p++) {
>+        const char *name = *p;
>+
>+        if (qemuMonitorJSONGetObjectProperty(mon, QOM_CPU_PATH, name, &prop) < 0)
>+            goto cleanup;
>+
>+        if (!prop.val.b)
>+            continue;
>+
>+        if (translate)
>+            name = translate(name, opaque);
>+
>+        if (virCPUDataAddFeature(data, name) < 0)
>+            goto cleanup;
>+    }
>+
>+    ret = 0;
>+
>+ cleanup:
>+    virStringListFree(props);
>+    return ret;
>+}
>+
>+
>+static int
>+qemuMonitorJSONGetCPUDataDisabled(qemuMonitorPtr mon,
>+                                  qemuMonitorCPUFeatureTranslationCallback translate,
>+                                  void *opaque,
>+                                  virCPUDataPtr data)
>+{
>+    char **props;

VIR_AUTOSTRINGLIST props = NULL;

>+    char **p;
>+    int ret = -1;
>+
>+    if (qemuMonitorJSONGetStringListProperty(mon, QOM_CPU_PATH,
>+                                             "unavailable-features", &props) < 0)
>+        goto cleanup;
>+
>+    for (p = props; p && *p; p++) {
>+        const char *name = *p;
>+
>+        if (translate)
>+            name = translate(name, opaque);
>+

Reviewed-by: Ján Tomko <jtomko@redhat.com>

Jano
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list