Blame SOURCES/libvirt-qemu-monitor-Return-struct-from-qemuMonitor-Text-Json-QueryCPUs.patch

6ae9ed
From ea8dd0fe977164f2530c8e87c31c2adb732d4239 Mon Sep 17 00:00:00 2001
6ae9ed
Message-Id: <ea8dd0fe977164f2530c8e87c31c2adb732d4239@dist-git>
6ae9ed
From: Peter Krempa <pkrempa@redhat.com>
6ae9ed
Date: Wed, 24 Aug 2016 16:11:18 -0400
6ae9ed
Subject: [PATCH] qemu: monitor: Return struct from
6ae9ed
 qemuMonitor(Text|Json)QueryCPUs
6ae9ed
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1097930
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1224341
6ae9ed
6ae9ed
Prepare to extract more data by returning an array of structs rather than
6ae9ed
just an array of thread ids. Additionally report fatal errors separately
6ae9ed
from qemu not being able to produce data.
6ae9ed
6ae9ed
(cherry picked from commit b3180425ce0ac01948cd997d56b4af21a5380438)
6ae9ed
---
6ae9ed
 src/qemu/qemu_monitor.c      | 31 ++++++++++++------
6ae9ed
 src/qemu/qemu_monitor.h      |  6 ++++
6ae9ed
 src/qemu/qemu_monitor_json.c | 77 +++++++++++++++++++++++---------------------
6ae9ed
 src/qemu/qemu_monitor_json.h |  3 +-
6ae9ed
 src/qemu/qemu_monitor_text.c | 41 +++++++++++------------
6ae9ed
 src/qemu/qemu_monitor_text.h |  3 +-
6ae9ed
 tests/qemumonitorjsontest.c  | 39 +++++++++++++++-------
6ae9ed
 7 files changed, 121 insertions(+), 79 deletions(-)
6ae9ed
6ae9ed
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
6ae9ed
index c3b9f41..d5af7d1 100644
6ae9ed
--- a/src/qemu/qemu_monitor.c
6ae9ed
+++ b/src/qemu/qemu_monitor.c
6ae9ed
@@ -1661,6 +1661,16 @@ qemuMonitorCPUInfoFree(qemuMonitorCPUInfoPtr cpus,
6ae9ed
     VIR_FREE(cpus);
6ae9ed
 }
6ae9ed
 
6ae9ed
+void
6ae9ed
+qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
6ae9ed
+                         size_t nentries ATTRIBUTE_UNUSED)
6ae9ed
+{
6ae9ed
+    if (!entries)
6ae9ed
+        return;
6ae9ed
+
6ae9ed
+    VIR_FREE(entries);
6ae9ed
+}
6ae9ed
+
6ae9ed
 
6ae9ed
 /**
6ae9ed
  * qemuMonitorGetCPUInfo:
6ae9ed
@@ -1681,7 +1691,8 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
6ae9ed
                       size_t maxvcpus)
6ae9ed
 {
6ae9ed
     qemuMonitorCPUInfoPtr info = NULL;
6ae9ed
-    int *pids = NULL;
6ae9ed
+    struct qemuMonitorQueryCpusEntry *cpuentries = NULL;
6ae9ed
+    size_t ncpuentries = 0;
6ae9ed
     size_t i;
6ae9ed
     int ret = -1;
6ae9ed
     int rc;
6ae9ed
@@ -1692,26 +1703,28 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
6ae9ed
         return -1;
6ae9ed
 
6ae9ed
     if (mon->json)
6ae9ed
-        rc = qemuMonitorJSONQueryCPUs(mon, &pids);
6ae9ed
+        rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries);
6ae9ed
     else
6ae9ed
-        rc = qemuMonitorTextQueryCPUs(mon, &pids);
6ae9ed
+        rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries);
6ae9ed
 
6ae9ed
     if (rc < 0) {
6ae9ed
-        virResetLastError();
6ae9ed
-        VIR_STEAL_PTR(*vcpus, info);
6ae9ed
-        ret = 0;
6ae9ed
+        if (rc == -2) {
6ae9ed
+            VIR_STEAL_PTR(*vcpus, info);
6ae9ed
+            ret = 0;
6ae9ed
+        }
6ae9ed
+
6ae9ed
         goto cleanup;
6ae9ed
     }
6ae9ed
 
6ae9ed
-    for (i = 0; i < rc; i++)
6ae9ed
-        info[i].tid = pids[i];
6ae9ed
+    for (i = 0; i < ncpuentries; i++)
6ae9ed
+        info[i].tid = cpuentries[i].tid;
6ae9ed
 
6ae9ed
     VIR_STEAL_PTR(*vcpus, info);
6ae9ed
     ret = 0;
6ae9ed
 
6ae9ed
  cleanup:
6ae9ed
     qemuMonitorCPUInfoFree(info, maxvcpus);
6ae9ed
-    VIR_FREE(pids);
6ae9ed
+    qemuMonitorQueryCpusFree(cpuentries, ncpuentries);
6ae9ed
     return ret;
6ae9ed
 }
6ae9ed
 
6ae9ed
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
6ae9ed
index 3ab3f08..5ec2101 100644
6ae9ed
--- a/src/qemu/qemu_monitor.h
6ae9ed
+++ b/src/qemu/qemu_monitor.h
6ae9ed
@@ -390,6 +390,12 @@ int qemuMonitorGetStatus(qemuMonitorPtr mon,
6ae9ed
 int qemuMonitorSystemReset(qemuMonitorPtr mon);
6ae9ed
 int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
6ae9ed
 
6ae9ed
+struct qemuMonitorQueryCpusEntry {
6ae9ed
+    pid_t tid;
6ae9ed
+};
6ae9ed
+void qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
6ae9ed
+                              size_t nentries);
6ae9ed
+
6ae9ed
 
6ae9ed
 struct _qemuMonitorCPUInfo {
6ae9ed
     pid_t tid;
6ae9ed
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
6ae9ed
index a45772e..5836e1e 100644
6ae9ed
--- a/src/qemu/qemu_monitor_json.c
6ae9ed
+++ b/src/qemu/qemu_monitor_json.c
6ae9ed
@@ -1329,69 +1329,69 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
6ae9ed
  *   { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
6ae9ed
  */
6ae9ed
 static int
6ae9ed
-qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
6ae9ed
-                              int **pids)
6ae9ed
+qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
6ae9ed
+                              struct qemuMonitorQueryCpusEntry **entries,
6ae9ed
+                              size_t *nentries)
6ae9ed
 {
6ae9ed
-    virJSONValuePtr data;
6ae9ed
+    struct qemuMonitorQueryCpusEntry *cpus = NULL;
6ae9ed
     int ret = -1;
6ae9ed
     size_t i;
6ae9ed
-    int *threads = NULL;
6ae9ed
     ssize_t ncpus;
6ae9ed
 
6ae9ed
-    if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
6ae9ed
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6ae9ed
-                       _("cpu reply was missing return data"));
6ae9ed
-        goto cleanup;
6ae9ed
-    }
6ae9ed
+    if ((ncpus = virJSONValueArraySize(data)) <= 0)
6ae9ed
+        return -2;
6ae9ed
 
6ae9ed
-    if ((ncpus = virJSONValueArraySize(data)) <= 0) {
6ae9ed
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6ae9ed
-                       _("cpu information was empty"));
6ae9ed
-        goto cleanup;
6ae9ed
-    }
6ae9ed
-
6ae9ed
-    if (VIR_ALLOC_N(threads, ncpus) < 0)
6ae9ed
+    if (VIR_ALLOC_N(cpus, ncpus) < 0)
6ae9ed
         goto cleanup;
6ae9ed
 
6ae9ed
     for (i = 0; i < ncpus; i++) {
6ae9ed
         virJSONValuePtr entry = virJSONValueArrayGet(data, i);
6ae9ed
-        int thread;
6ae9ed
+        int thread = 0;
6ae9ed
         if (!entry) {
6ae9ed
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6ae9ed
-                           _("cpu information was missing an array element"));
6ae9ed
+            ret = -2;
6ae9ed
             goto cleanup;
6ae9ed
         }
6ae9ed
 
6ae9ed
-        if (virJSONValueObjectGetNumberInt(entry, "thread_id", &thread) < 0) {
6ae9ed
-            /* Some older qemu versions don't report the thread_id,
6ae9ed
-             * so treat this as non-fatal, simply returning no data */
6ae9ed
-            ret = 0;
6ae9ed
-            goto cleanup;
6ae9ed
-        }
6ae9ed
+        /* Some older qemu versions don't report the thread_id so treat this as
6ae9ed
+         * non-fatal, simply returning no data */
6ae9ed
+        ignore_value(virJSONValueObjectGetNumberInt(entry, "thread_id", &thread));
6ae9ed
 
6ae9ed
-        threads[i] = thread;
6ae9ed
+        cpus[i].tid = thread;
6ae9ed
     }
6ae9ed
 
6ae9ed
-    *pids = threads;
6ae9ed
-    threads = NULL;
6ae9ed
-    ret = ncpus;
6ae9ed
+    VIR_STEAL_PTR(*entries, cpus);
6ae9ed
+    *nentries = ncpus;
6ae9ed
+    ret = 0;
6ae9ed
 
6ae9ed
  cleanup:
6ae9ed
-    VIR_FREE(threads);
6ae9ed
+    qemuMonitorQueryCpusFree(cpus, ncpus);
6ae9ed
     return ret;
6ae9ed
 }
6ae9ed
 
6ae9ed
 
6ae9ed
+/**
6ae9ed
+ * qemuMonitorJSONQueryCPUs:
6ae9ed
+ *
6ae9ed
+ * @mon: monitor object
6ae9ed
+ * @entries: filled with detected entries on success
6ae9ed
+ * @nentries: number of entries returned
6ae9ed
+ *
6ae9ed
+ * Queries qemu for cpu-related information. Failure to execute the command or
6ae9ed
+ * extract results does not produce an error as libvirt can continue without
6ae9ed
+ * this information.
6ae9ed
+ *
6ae9ed
+ * Returns 0 on success success, -1 on a fatal error (oom ...) and -2 if the
6ae9ed
+ * query failed gracefully.
6ae9ed
+ */
6ae9ed
 int
6ae9ed
 qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
6ae9ed
-                         int **pids)
6ae9ed
+                         struct qemuMonitorQueryCpusEntry **entries,
6ae9ed
+                         size_t *nentries)
6ae9ed
 {
6ae9ed
     int ret = -1;
6ae9ed
-    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus",
6ae9ed
-                                                     NULL);
6ae9ed
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL);
6ae9ed
     virJSONValuePtr reply = NULL;
6ae9ed
-
6ae9ed
-    *pids = NULL;
6ae9ed
+    virJSONValuePtr data;
6ae9ed
 
6ae9ed
     if (!cmd)
6ae9ed
         return -1;
6ae9ed
@@ -1399,10 +1399,13 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
6ae9ed
     if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6ae9ed
         goto cleanup;
6ae9ed
 
6ae9ed
-    if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6ae9ed
+    if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
6ae9ed
+        ret = -2;
6ae9ed
         goto cleanup;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    ret = qemuMonitorJSONExtractCPUInfo(data, entries, nentries);
6ae9ed
 
6ae9ed
-    ret = qemuMonitorJSONExtractCPUInfo(reply, pids);
6ae9ed
  cleanup:
6ae9ed
     virJSONValueFree(cmd);
6ae9ed
     virJSONValueFree(reply);
6ae9ed
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
6ae9ed
index ef198b4..2a439da 100644
6ae9ed
--- a/src/qemu/qemu_monitor_json.h
6ae9ed
+++ b/src/qemu/qemu_monitor_json.h
6ae9ed
@@ -59,7 +59,8 @@ int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
6ae9ed
 int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
6ae9ed
 
6ae9ed
 int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
6ae9ed
-                             int **pids);
6ae9ed
+                             struct qemuMonitorQueryCpusEntry **entries,
6ae9ed
+                             size_t *nentries);
6ae9ed
 int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
6ae9ed
                                virDomainVirtType *virtType);
6ae9ed
 int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
6ae9ed
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
6ae9ed
index 0b05587..e29acfc 100644
6ae9ed
--- a/src/qemu/qemu_monitor_text.c
6ae9ed
+++ b/src/qemu/qemu_monitor_text.c
6ae9ed
@@ -502,12 +502,15 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon)
6ae9ed
 
6ae9ed
 int
6ae9ed
 qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
6ae9ed
-                         int **pids)
6ae9ed
+                         struct qemuMonitorQueryCpusEntry **entries,
6ae9ed
+                         size_t *nentries)
6ae9ed
 {
6ae9ed
     char *qemucpus = NULL;
6ae9ed
     char *line;
6ae9ed
-    pid_t *cpupids = NULL;
6ae9ed
-    size_t ncpupids = 0;
6ae9ed
+    struct qemuMonitorQueryCpusEntry *cpus = NULL;
6ae9ed
+    size_t ncpus = 0;
6ae9ed
+    struct qemuMonitorQueryCpusEntry cpu = {0};
6ae9ed
+    int ret = -2; /* -2 denotes a non-fatal error to get the data */
6ae9ed
 
6ae9ed
     if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
6ae9ed
         return -1;
6ae9ed
@@ -529,15 +532,19 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
6ae9ed
 
6ae9ed
         /* Extract host Thread ID */
6ae9ed
         if ((offset = strstr(line, "thread_id=")) == NULL)
6ae9ed
-            goto error;
6ae9ed
+            goto cleanup;
6ae9ed
 
6ae9ed
         if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0)
6ae9ed
-            goto error;
6ae9ed
+            goto cleanup;
6ae9ed
         if (end == NULL || !c_isspace(*end))
6ae9ed
-            goto error;
6ae9ed
+            goto cleanup;
6ae9ed
 
6ae9ed
-        if (VIR_APPEND_ELEMENT_COPY(cpupids, ncpupids, tid) < 0)
6ae9ed
-            goto error;
6ae9ed
+        cpu.tid = tid;
6ae9ed
+
6ae9ed
+        if (VIR_APPEND_ELEMENT_COPY(cpus, ncpus, cpu) < 0) {
6ae9ed
+            ret = -1;
6ae9ed
+            goto cleanup;
6ae9ed
+        }
6ae9ed
 
6ae9ed
         VIR_DEBUG("tid=%d", tid);
6ae9ed
 
6ae9ed
@@ -547,20 +554,14 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
6ae9ed
             line = strchr(offset, '\n');
6ae9ed
     } while (line != NULL);
6ae9ed
 
6ae9ed
-    /* Validate we got data for all VCPUs we expected */
6ae9ed
-    VIR_FREE(qemucpus);
6ae9ed
-    *pids = cpupids;
6ae9ed
-    return ncpupids;
6ae9ed
+    VIR_STEAL_PTR(*entries, cpus);
6ae9ed
+    *nentries = ncpus;
6ae9ed
+    ret = 0;
6ae9ed
 
6ae9ed
- error:
6ae9ed
+ cleanup:
6ae9ed
+    qemuMonitorQueryCpusFree(cpus, ncpus);
6ae9ed
     VIR_FREE(qemucpus);
6ae9ed
-    VIR_FREE(cpupids);
6ae9ed
-
6ae9ed
-    /* Returning 0 to indicate non-fatal failure, since
6ae9ed
-     * older QEMU does not have VCPU<->PID mapping and
6ae9ed
-     * we don't want to fail on that
6ae9ed
-     */
6ae9ed
-    return 0;
6ae9ed
+    return ret;
6ae9ed
 }
6ae9ed
 
6ae9ed
 
6ae9ed
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
6ae9ed
index b7f0cab..86f43e7 100644
6ae9ed
--- a/src/qemu/qemu_monitor_text.h
6ae9ed
+++ b/src/qemu/qemu_monitor_text.h
6ae9ed
@@ -50,7 +50,8 @@ int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
6ae9ed
 int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
6ae9ed
 
6ae9ed
 int qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
6ae9ed
-                             int **pids);
6ae9ed
+                             struct qemuMonitorQueryCpusEntry **entries,
6ae9ed
+                             size_t *nentries);
6ae9ed
 int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
6ae9ed
                                virDomainVirtType *virtType);
6ae9ed
 int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
6ae9ed
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
6ae9ed
index 1d245d0..3fd4eb6 100644
6ae9ed
--- a/tests/qemumonitorjsontest.c
6ae9ed
+++ b/tests/qemumonitorjsontest.c
6ae9ed
@@ -1201,6 +1201,16 @@ GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart, "localhost", 12345)
6ae9ed
 GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
6ae9ed
 GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
6ae9ed
 
6ae9ed
+static bool
6ae9ed
+testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct qemuMonitorQueryCpusEntry *a,
6ae9ed
+                                                 struct qemuMonitorQueryCpusEntry *b)
6ae9ed
+{
6ae9ed
+    if (a->tid != b->tid)
6ae9ed
+        return false;
6ae9ed
+
6ae9ed
+    return true;
6ae9ed
+}
6ae9ed
+
6ae9ed
 
6ae9ed
 static int
6ae9ed
 testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
6ae9ed
@@ -1208,9 +1218,14 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
6ae9ed
     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
6ae9ed
     qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
6ae9ed
     int ret = -1;
6ae9ed
-    pid_t *cpupids = NULL;
6ae9ed
-    pid_t expected_cpupids[] = {17622, 17624, 17626, 17628};
6ae9ed
-    int ncpupids;
6ae9ed
+    struct qemuMonitorQueryCpusEntry *cpudata = NULL;
6ae9ed
+    struct qemuMonitorQueryCpusEntry expect[] = {
6ae9ed
+        {17622},
6ae9ed
+        {17624},
6ae9ed
+        {17626},
6ae9ed
+        {17628},
6ae9ed
+    };
6ae9ed
+    size_t ncpudata = 0;
6ae9ed
     size_t i;
6ae9ed
 
6ae9ed
     if (!test)
6ae9ed
@@ -1252,19 +1267,21 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
6ae9ed
                                "}") < 0)
6ae9ed
         goto cleanup;
6ae9ed
 
6ae9ed
-    ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpupids);
6ae9ed
+    if (qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test),
6ae9ed
+                                 &cpudata, &ncpudata) < 0)
6ae9ed
+        goto cleanup;
6ae9ed
 
6ae9ed
-    if (ncpupids != 4) {
6ae9ed
+    if (ncpudata != 4) {
6ae9ed
         virReportError(VIR_ERR_INTERNAL_ERROR,
6ae9ed
-                       "Expecting ncpupids = 4 but got %d", ncpupids);
6ae9ed
+                       "Expecting ncpupids = 4 but got %zu", ncpudata);
6ae9ed
         goto cleanup;
6ae9ed
     }
6ae9ed
 
6ae9ed
-    for (i = 0; i < ncpupids; i++) {
6ae9ed
-        if (cpupids[i] != expected_cpupids[i]) {
6ae9ed
+    for (i = 0; i < ncpudata; i++) {
6ae9ed
+        if (!testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(cpudata + i,
6ae9ed
+                                                              expect + i)) {
6ae9ed
             virReportError(VIR_ERR_INTERNAL_ERROR,
6ae9ed
-                           "Expecting cpupids[%zu] = %d but got %d",
6ae9ed
-                           i, expected_cpupids[i], cpupids[i]);
6ae9ed
+                           "vcpu entry %zu does not match expected data", i);
6ae9ed
             goto cleanup;
6ae9ed
         }
6ae9ed
     }
6ae9ed
@@ -1272,7 +1289,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
6ae9ed
     ret = 0;
6ae9ed
 
6ae9ed
  cleanup:
6ae9ed
-    VIR_FREE(cpupids);
6ae9ed
+    qemuMonitorQueryCpusFree(cpudata, ncpudata);
6ae9ed
     qemuMonitorTestFree(test);
6ae9ed
     return ret;
6ae9ed
 }
6ae9ed
-- 
6ae9ed
2.10.0
6ae9ed