[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