Extract architecture specific data from query-cpus[-fast] if
available. A new function qemuMonitorJSONExtractCPUArchInfo()
uses a call-back table to find and call architecture-specific
extraction handlers.
Initially, there's a handler for s390 cpu info to
set the halted property depending on the s390 cpu state
returned by QEMU. With this it's still possible to report
the halted condition even when using query-cpus-fast.
Signed-off-by: Viktor Mihajlovski <mihajlov(a)linux.vnet.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
---
src/qemu/qemu_monitor.c | 6 ++-
src/qemu/qemu_monitor_json.c | 123 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 126 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index dad1383..5a0e8a7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2083,12 +2083,16 @@ qemuMonitorGetCpuHalted(qemuMonitorPtr mon,
size_t i;
int rc;
virBitmapPtr ret = NULL;
+ bool fast;
QEMU_CHECK_MONITOR_NULL(mon);
+ fast = virQEMUCapsGet(QEMU_DOMAIN_PRIVATE(mon->vm)->qemuCaps,
+ QEMU_CAPS_QUERY_CPUS_FAST);
+
if (mon->json)
rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries, false,
- false);
+ fast);
else
rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2ecdf0a..a408cfd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1451,15 +1451,128 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
}
-/*
+typedef struct {
+ const char *state;
+ bool halted;
+} s390CpuStateMap;
+
+/**
+ * qemuMonitorJSONExtractCPUS390Info:
+ * @jsoncpu: pointer to a single JSON cpu entry
+ * @cpu: pointer to a single cpu entry
+ *
+ * Derive the legacy cpu info 'halted' information
+ * from the more accurate s390 cpu state. @cpu is
+ * modified only on success.
+ *
+ * Note: the 'uninitialized' s390 cpu state can't be
+ * mapped to halted yes/no.
+ *
+ * A s390 cpu entry could look like this
+ * { "arch": "s390",
+ * "cpu-index": 0,
+ * "qom-path": "/machine/unattached/device[0]",
+ * "thread_id": 3081,
+ * "cpu-state": "operating" }
+ *
+ * Returns 0 on success, and -2 if no cpu-state field was
+ * found or the state value is unknown.
+ */
+static int
+qemuMonitorJSONExtractCPUS390Info(virJSONValuePtr jsoncpu,
+ struct qemuMonitorQueryCpusEntry *cpu)
+{
+ const char *cpu_state;
+ s390CpuStateMap states[] = {
+ { "operating", false},
+ { "load", false},
+ { "stopped", true},
+ { "check-stop", true},
+ };
+ size_t i;
+
+ if ((cpu_state = virJSONValueObjectGetString(jsoncpu, "cpu-state"))) {
+ for (i = 0; i < ARRAY_CARDINALITY(states); i++) {
+ if (STREQ(states[i].state, cpu_state)) {
+ cpu->halted = states[i].halted;
+ return 0;
+ }
+ }
+ }
+
+ return -2;
+}
+
+typedef struct {
+ const char *arch;
+ int (*extract)(virJSONValuePtr jsoncpu,
+ struct qemuMonitorQueryCpusEntry *cpu);
+} qemuCpuArchInfoHandler;
+
+
+/**
+ * qemuMonitorJSONExtractCPUArchInfo:
+ * @arch: virtual CPU's architecture
+ * @jsoncpu: pointer to a single JSON cpu entry
+ * @cpu: pointer to a single cpu entry
+ *
+ * Extracts architecure specific virtual CPU data for a single
+ * CPU from the QAPI response using an architecture specific
+ * callback.
*
+ * To add a support for a new architecture, extend the array
+ * 'handlers' with a line like
+ * ...
+ * { "newarch", qemuMonitorJSONExtractCPUNewarch },
+ * ...
+ * and implement the extraction callback.
+ * Check the QEMU QAPI schema for valid architecture names.
+ *
+ * Returns the called handler's return value or 0, if no handler
+ * was called.
+ */
+static int
+qemuMonitorJSONExtractCPUArchInfo(const char *arch, virJSONValuePtr jsoncpu,
+ struct qemuMonitorQueryCpusEntry *cpu)
+{
+ qemuCpuArchInfoHandler handlers[] = {
+ { "s390", qemuMonitorJSONExtractCPUS390Info },
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_CARDINALITY(handlers); i++) {
+ if (STREQ(handlers[i].arch, arch))
+ return handlers[i].extract(jsoncpu, cpu);
+ }
+
+ return 0;
+}
+
+/**
+ * qemuMonitorJSONExtractCPUArchInfo:
+ * @data: JSON response data
+ * @entries: filled with detected cpu entries on success
+ * @nentries: number of entries returned
+ * @fast: true if this is a response from query-cpus-fast
+ *
+ * The JSON response @data will have the following format
+ * in case @fast == false
* [{ "arch": "x86",
* "current": true,
* "CPU": 0,
* "qom_path": "/machine/unattached/device[0]",
* "pc": -2130415978,
* "halted": true,
- * "thread_id": 2631237},
+ * "thread_id": 2631237,
+ * ...},
+ * {...}
+ * ]
+ * and for @fast == true
+ * [{ "arch": "x86",
+ * "cpu-index": 0,
+ * "qom-path": "/machine/unattached/device[0]",
+ * "thread_id": 2631237,
+ * ...},
* {...}
* ]
*/
@@ -1486,6 +1599,7 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
int thread = 0;
bool halted = false;
const char *qom_path;
+ const char *arch;
if (!entry) {
ret = -2;
goto cleanup;
@@ -1505,6 +1619,11 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
cpus[i].halted = halted;
if (VIR_STRDUP(cpus[i].qom_path, qom_path) < 0)
goto cleanup;
+
+ /* process optional architecture-specific data */
+ if ((arch = virJSONValueObjectGetString(entry, "arch")))
+ ignore_value(qemuMonitorJSONExtractCPUArchInfo(arch, entry,
+ cpus + i));
}
VIR_STEAL_PTR(*entries, cpus);
--
1.9.1