[libvirt] [PATCH 10/10] qemu: monitor: Return struct from qemuMonitor(Text|Json)QueryCPUs
John Ferlan
jferlan at redhat.com
Wed Aug 3 16:04:02 UTC 2016
On 08/03/2016 04:11 AM, Peter Krempa wrote:
> Prepare to extract more data by returning a array of structs rather than
> just an array of thread ids. Additionally report fatal errors separately
> from qemu not being able to produce data.
> ---
> src/qemu/qemu_monitor.c | 31 ++++++++++++-------
> src/qemu/qemu_monitor.h | 6 ++++
> src/qemu/qemu_monitor_json.c | 71 ++++++++++++++++++++++----------------------
> src/qemu/qemu_monitor_json.h | 2 +-
> src/qemu/qemu_monitor_text.c | 37 +++++++++++------------
> src/qemu/qemu_monitor_text.h | 2 +-
> tests/qemumonitorjsontest.c | 31 ++++++++++++++-----
> 7 files changed, 104 insertions(+), 76 deletions(-)
>
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 0011ceb..578b078 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1666,6 +1666,16 @@ qemuMonitorCPUInfoFree(qemuMonitorCPUInfoPtr cpus,
> VIR_FREE(cpus);
> }
>
> +void
> +qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
> + size_t nentries ATTRIBUTE_UNUSED)
> +{
> + if (!entries)
> + return;
[1] Maybe this should be a 'int' parameter and a <= 0 check...
> +
> + VIR_FREE(entries);
> +}
> +
>
> /**
> * qemuMonitorGetCPUInfo:
> @@ -1686,10 +1696,10 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
> size_t maxvcpus)
> {
> qemuMonitorCPUInfoPtr info = NULL;
> - int *pids = NULL;
> + struct qemuMonitorQueryCpusEntry *cpuentries = NULL;
> size_t i;
> int ret = -1;
> - int rc;
> + int ncpuentries;
>
> QEMU_CHECK_MONITOR(mon);
>
> @@ -1697,25 +1707,26 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
> return -1;
>
> if (mon->json)
> - rc = qemuMonitorJSONQueryCPUs(mon, &pids);
> + ncpuentries = qemuMonitorJSONQueryCPUs(mon, &cpuentries);
> else
> - rc = qemuMonitorTextQueryCPUs(mon, &pids);
> + ncpuentries = qemuMonitorTextQueryCPUs(mon, &cpuentries);
> +
> + if (ncpuentries < 0) {
> + if (ncpuentries == -2)
> + ret = 0;
Similar to previous patch w/r/t "ret = 0" and returning to caller
>
> - if (rc < 0) {
> - virResetLastError();
> - ret = 0;
> goto cleanup;
> }
>
> - for (i = 0; i < rc; i++)
> - info[i].tid = pids[i];
> + for (i = 0; i < ncpuentries; i++)
> + info[i].tid = cpuentries[i].tid;
>
> VIR_STEAL(*vcpus, info);
> ret = 0;
>
> cleanup:
> qemuMonitorCPUInfoFree(info, maxvcpus);
> - VIR_FREE(pids);
> + qemuMonitorQueryCpusFree(cpuentries, ncpuentries);
[1]Although not "currently" used, the ncpuentries is an int being passed
to a function that wants size_t
And yes, that's from a Coverity warning
> return ret;
> }
>
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 1ef002a..6022b9d 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -390,6 +390,12 @@ int qemuMonitorGetStatus(qemuMonitorPtr mon,
> int qemuMonitorSystemReset(qemuMonitorPtr mon);
> int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
>
> +struct qemuMonitorQueryCpusEntry {
> + pid_t tid;
> +};
> +void qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
> + size_t nentries);
> +
>
> struct _qemuMonitorCPUInfo {
> pid_t tid;
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 715e1c7..8018860 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -1323,69 +1323,65 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
> * { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
> */
> static int
> -qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
> - int **pids)
> +qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
> + struct qemuMonitorQueryCpusEntry **entries)
> {
> - virJSONValuePtr data;
> + struct qemuMonitorQueryCpusEntry *cpus = NULL;
> int ret = -1;
> size_t i;
> - int *threads = NULL;
> ssize_t ncpus;
>
> - if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("cpu reply was missing return data"));
> - goto cleanup;
> - }
> -
> - if ((ncpus = virJSONValueArraySize(data)) <= 0) {
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("cpu information was empty"));
> - goto cleanup;
> - }
> + if ((ncpus = virJSONValueArraySize(data)) <= 0)
> + return -2;
>
> - if (VIR_ALLOC_N(threads, ncpus) < 0)
> + if (VIR_ALLOC_N(cpus, ncpus) < 0)
> goto cleanup;
>
> for (i = 0; i < ncpus; i++) {
> virJSONValuePtr entry = virJSONValueArrayGet(data, i);
> - int thread;
> + int thread = 0;
> if (!entry) {
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("cpu information was missing an array element"));
> + ret = -2;
> goto cleanup;
> }
>
> - if (virJSONValueObjectGetNumberInt(entry, "thread_id", &thread) < 0) {
> - /* Some older qemu versions don't report the thread_id,
> - * so treat this as non-fatal, simply returning no data */
> - ret = 0;
> - goto cleanup;
> - }
> + /* Some older qemu versions don't report the thread_id so treat this as
> + * non-fatal, simply returning no data */
> + ignore_value(virJSONValueObjectGetNumberInt(entry, "thread_id", &thread));
So we're going to still make 'ncpus' calls to get the same answer...
Then we're going to return 5 elements with {0, 0, 0, 0, 0} and the
caller is going to do what? I think eventually we'll end up failing in
qemuDomainValidateVcpuInfo.
>
> - threads[i] = thread;
> + cpus[i].tid = thread;
> }
>
> - *pids = threads;
> - threads = NULL;
> + VIR_STEAL(*entries, cpus);
> ret = ncpus;
>
> cleanup:
> - VIR_FREE(threads);
> + qemuMonitorQueryCpusFree(cpus, ncpus);
> return ret;
> }
>
>
> +/**
> + * qemuMonitorJSONQueryCPUs:
> + *
> + * @mon: monitor object
> + * @entries: filled with detected entries on success
> + *
> + * Queries qemu for cpu-related information. Failure to execute the command or
> + * extract results does not produce an error as libvirt can continue without
> + * this information.
> + *
> + * Returns number of cpu data entries returned in @entries on success, -1 on a
> + * fatal error (oom ...) and -2 if the query failed gracefully.
> + */
> int
> qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
> - int **pids)
> + struct qemuMonitorQueryCpusEntry **entries)
> {
> int ret = -1;
> - virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus",
> - NULL);
> + virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL);
> virJSONValuePtr reply = NULL;
> -
> - *pids = NULL;
> + virJSONValuePtr data;
>
> if (!cmd)
> return -1;
> @@ -1393,10 +1389,13 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
> if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
> goto cleanup;
>
> - if (qemuMonitorJSONCheckError(cmd, reply) < 0)
> + if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
> + ret = -2;
> goto cleanup;
> + }
> +
> + ret = qemuMonitorJSONExtractCPUInfo(data, entries);
>
> - ret = qemuMonitorJSONExtractCPUInfo(reply, pids);
> cleanup:
> virJSONValueFree(cmd);
> virJSONValueFree(reply);
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index 174f0ef..24b23d2 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -59,7 +59,7 @@ int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
> int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
>
> int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
> - int **pids);
> + struct qemuMonitorQueryCpusEntry **entries);
> int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
> virDomainVirtType *virtType);
> int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
> diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
> index ca04965..648c7db 100644
> --- a/src/qemu/qemu_monitor_text.c
> +++ b/src/qemu/qemu_monitor_text.c
> @@ -502,12 +502,14 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon)
>
> int
> qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
> - int **pids)
> + struct qemuMonitorQueryCpusEntry **entries)
> {
> char *qemucpus = NULL;
> char *line;
> - pid_t *cpupids = NULL;
> - size_t ncpupids = 0;
> + struct qemuMonitorQueryCpusEntry *cpus = NULL;
> + size_t ncpus;
Need to initialize to 0 (surprised neither compiler nor Coverity picked
up on it).
> + struct qemuMonitorQueryCpusEntry cpu = {0};
> + int ret = -2; /* -2 denotes a non-fatal error to get the data */
>
> if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
> return -1;
> @@ -529,15 +531,17 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
>
> /* Extract host Thread ID */
> if ((offset = strstr(line, "thread_id=")) == NULL)
> - goto error;
> + goto cleanup;
>
> if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0)
> - goto error;
> + goto cleanup;
> if (end == NULL || !c_isspace(*end))
> - goto error;
> + goto cleanup;
>
> - if (VIR_APPEND_ELEMENT_COPY(cpupids, ncpupids, tid) < 0)
> - goto error;
> + cpu.tid = tid;
> +
> + if (VIR_APPEND_ELEMENT_COPY(cpus, ncpus, cpu) < 0)
> + goto cleanup;
>
> VIR_DEBUG("tid=%d", tid);
>
> @@ -547,20 +551,13 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
> line = strchr(offset, '\n');
> } while (line != NULL);
>
> - /* Validate we got data for all VCPUs we expected */
> - VIR_FREE(qemucpus);
> - *pids = cpupids;
> - return ncpupids;
> + VIR_STEAL(*entries, cpus);
> + ret = ncpus;
>
> - error:
> + cleanup:
> + qemuMonitorQueryCpusFree(cpus, ncpus);
> VIR_FREE(qemucpus);
> - VIR_FREE(cpupids);
> -
> - /* Returning 0 to indicate non-fatal failure, since
> - * older QEMU does not have VCPU<->PID mapping and
> - * we don't want to fail on that
> - */
> - return 0;
> + return ret;
> }
>
>
> diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
> index b7f0cab..f9e0f82 100644
> --- a/src/qemu/qemu_monitor_text.h
> +++ b/src/qemu/qemu_monitor_text.h
> @@ -50,7 +50,7 @@ int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
> int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
>
> int qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
> - int **pids);
> + struct qemuMonitorQueryCpusEntry **entries);
> int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
> virDomainVirtType *virtType);
> int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
> diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
> index 544b569..f848d80 100644
> --- a/tests/qemumonitorjsontest.c
> +++ b/tests/qemumonitorjsontest.c
Just a thought... should we have a test that returns "0" entries - does
it make sense?
I think this is close, but needs a few tweaks or explanation before ACK
John
> @@ -1201,6 +1201,16 @@ GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart, "localhost", 12345)
> GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
> GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
>
> +static bool
> +testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct qemuMonitorQueryCpusEntry *a,
> + struct qemuMonitorQueryCpusEntry *b)
> +{
> + if (a->tid != b->tid)
> + return false;
> +
> + return true;
> +}
> +
>
> static int
> testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
> @@ -1208,9 +1218,14 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
> virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
> qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
> int ret = -1;
> - pid_t *cpupids = NULL;
> - pid_t expected_cpupids[] = {17622, 17624, 17626, 17628};
> - int ncpupids;
> + struct qemuMonitorQueryCpusEntry *cpudata = NULL;
> + struct qemuMonitorQueryCpusEntry expect[] = {
> + {17622},
> + {17624},
> + {17626},
> + {17628},
> + };
> + int ncpupids = 0;
> size_t i;
>
> if (!test)
> @@ -1252,7 +1267,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
> "}") < 0)
> goto cleanup;
>
> - ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpupids);
> + ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpudata);
>
> if (ncpupids != 4) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> @@ -1261,10 +1276,10 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
> }
>
> for (i = 0; i < ncpupids; i++) {
> - if (cpupids[i] != expected_cpupids[i]) {
> + if (!testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(cpudata + i,
> + expect + i)) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> - "Expecting cpupids[%zu] = %d but got %d",
> - i, expected_cpupids[i], cpupids[i]);
> + "vcpu entry %zu does not match expected data", i);
> goto cleanup;
> }
> }
> @@ -1272,7 +1287,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
> ret = 0;
>
> cleanup:
> - VIR_FREE(cpupids);
> + qemuMonitorQueryCpusFree(cpudata, ncpupids);
> qemuMonitorTestFree(test);
> return ret;
> }
>
More information about the libvir-list
mailing list