Blame SOURCES/libvirt-qemu-monitor-return-block-stats-data-as-a-hash-to-avoid-disk-mixup.patch

9119d9
From 46a13012c80b732c4a1794bc237cdec7a9a65323 Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <46a13012c80b732c4a1794bc237cdec7a9a65323@dist-git>
9119d9
From: Peter Krempa <pkrempa@redhat.com>
9119d9
Date: Wed, 1 Oct 2014 11:20:21 +0200
9119d9
Subject: [PATCH] qemu: monitor: return block stats data as a hash to avoid
9119d9
 disk mixup
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1113116
9119d9
9119d9
The current block stats code matched up the disk name with the actual
9119d9
stats by the order in the data returned from qemu. This unfortunately
9119d9
isn't right as qemu may return the disks in any order. Fix this by
9119d9
returning a hash of stats and index them by the disk alias.
9119d9
9119d9
(cherry picked from commit 96c0f57a82ef73ca924b7333d1001f05ecf5df86)
9119d9
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 src/qemu/qemu_driver.c       |  44 ++++++++---------
9119d9
 src/qemu/qemu_monitor.c      |  14 ++----
9119d9
 src/qemu/qemu_monitor.h      |   6 +--
9119d9
 src/qemu/qemu_monitor_json.c | 111 ++++++++++++++++++++-----------------------
9119d9
 src/qemu/qemu_monitor_json.h |   4 +-
9119d9
 5 files changed, 81 insertions(+), 98 deletions(-)
9119d9
9119d9
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
9119d9
index 8e90cc6..1a16da7 100644
9119d9
--- a/src/qemu/qemu_driver.c
9119d9
+++ b/src/qemu/qemu_driver.c
9119d9
@@ -17714,24 +17714,18 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
 {
9119d9
     size_t i;
9119d9
     int ret = -1;
9119d9
-    int nstats = dom->def->ndisks;
9119d9
-    qemuBlockStatsPtr stats = NULL;
9119d9
+    int rc;
9119d9
+    virHashTablePtr stats = NULL;
9119d9
     qemuDomainObjPrivatePtr priv = dom->privateData;
9119d9
 
9119d9
     if (!HAVE_JOB(privflags) || !virDomainObjIsActive(dom))
9119d9
         return 0; /* it's ok, just go ahead silently */
9119d9
 
9119d9
-    if (VIR_ALLOC_N(stats, nstats) < 0)
9119d9
-        return -1;
9119d9
-
9119d9
     qemuDomainObjEnterMonitor(driver, dom);
9119d9
-
9119d9
-    nstats = qemuMonitorGetAllBlockStatsInfo(priv->mon, NULL,
9119d9
-                                             stats, nstats);
9119d9
-
9119d9
+    rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats);
9119d9
     qemuDomainObjExitMonitor(driver, dom);
9119d9
 
9119d9
-    if (nstats < 0) {
9119d9
+    if (rc < 0) {
9119d9
         virResetLastError();
9119d9
         ret = 0; /* still ok, again go ahead silently */
9119d9
         goto cleanup;
9119d9
@@ -17739,32 +17733,38 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
 
9119d9
     QEMU_ADD_COUNT_PARAM(record, maxparams, "block", dom->def->ndisks);
9119d9
 
9119d9
-    for (i = 0; i < nstats; i++) {
9119d9
-        QEMU_ADD_NAME_PARAM(record, maxparams,
9119d9
-                            "block", i, dom->def->disks[i]->dst);
9119d9
+    for (i = 0; i < dom->def->ndisks; i++) {
9119d9
+        qemuBlockStats *entry;
9119d9
+        virDomainDiskDefPtr disk = dom->def->disks[i];
9119d9
+
9119d9
+        QEMU_ADD_NAME_PARAM(record, maxparams, "block", i, disk->dst);
9119d9
+
9119d9
+        if (!disk->info.alias ||
9119d9
+            !(entry = virHashLookup(stats, disk->info.alias)))
9119d9
+            continue;
9119d9
 
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "rd.reqs", stats[i].rd_req);
9119d9
+                                "rd.reqs", entry->rd_req);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "rd.bytes", stats[i].rd_bytes);
9119d9
+                                "rd.bytes", entry->rd_bytes);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "rd.times", stats[i].rd_total_times);
9119d9
+                                "rd.times", entry->rd_total_times);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "wr.reqs", stats[i].wr_req);
9119d9
+                                "wr.reqs", entry->wr_req);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "wr.bytes", stats[i].wr_bytes);
9119d9
+                                "wr.bytes", entry->wr_bytes);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "wr.times", stats[i].wr_total_times);
9119d9
+                                "wr.times", entry->wr_total_times);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "fl.reqs", stats[i].flush_req);
9119d9
+                                "fl.reqs", entry->flush_req);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
-                                "fl.times", stats[i].flush_total_times);
9119d9
+                                "fl.times", entry->flush_total_times);
9119d9
     }
9119d9
 
9119d9
     ret = 0;
9119d9
 
9119d9
  cleanup:
9119d9
-    VIR_FREE(stats);
9119d9
+    virHashFree(stats);
9119d9
     return ret;
9119d9
 }
9119d9
 
9119d9
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
9119d9
index afe7959..93e8f22 100644
9119d9
--- a/src/qemu/qemu_monitor.c
9119d9
+++ b/src/qemu/qemu_monitor.c
9119d9
@@ -1767,23 +1767,17 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
9119d9
  */
9119d9
 int
9119d9
 qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
-                                const char *dev_name,
9119d9
-                                qemuBlockStatsPtr stats,
9119d9
-                                int nstats)
9119d9
+                                virHashTablePtr *ret_stats)
9119d9
 {
9119d9
-    int ret;
9119d9
-    VIR_DEBUG("mon=%p dev=%s", mon, dev_name);
9119d9
+    VIR_DEBUG("mon=%p ret_stats=%p", mon, ret_stats);
9119d9
 
9119d9
-    if (mon->json) {
9119d9
-        ret = qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name,
9119d9
-                                                  stats, nstats);
9119d9
-    } else {
9119d9
+    if (!mon->json) {
9119d9
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
                        _("unable to query all block stats with this QEMU"));
9119d9
         return -1;
9119d9
     }
9119d9
 
9119d9
-    return ret;
9119d9
+    return qemuMonitorJSONGetAllBlockStatsInfo(mon, ret_stats);
9119d9
 }
9119d9
 
9119d9
 /* Return 0 and update @nparams with the number of block stats
9119d9
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
9119d9
index b7f9fd1..2551272 100644
9119d9
--- a/src/qemu/qemu_monitor.h
9119d9
+++ b/src/qemu/qemu_monitor.h
9119d9
@@ -361,10 +361,8 @@ struct _qemuBlockStats {
9119d9
 };
9119d9
 
9119d9
 int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
-                                    const char *dev_name,
9119d9
-                                    qemuBlockStatsPtr stats,
9119d9
-                                    int nstats)
9119d9
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
9119d9
+                                    virHashTablePtr *ret_stats)
9119d9
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
9119d9
 
9119d9
 int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
9119d9
                                          int *nparams);
9119d9
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
9119d9
index c013d49..db553fb 100644
9119d9
--- a/src/qemu/qemu_monitor_json.c
9119d9
+++ b/src/qemu/qemu_monitor_json.c
9119d9
@@ -1708,7 +1708,8 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
9119d9
                                      long long *flush_total_times,
9119d9
                                      long long *errs)
9119d9
 {
9119d9
-    qemuBlockStats stats;
9119d9
+    qemuBlockStats *stats;
9119d9
+    virHashTablePtr blockstats = NULL;
9119d9
     int ret = -1;
9119d9
 
9119d9
     *rd_req = *rd_bytes = -1;
9119d9
@@ -1723,56 +1724,61 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
9119d9
     if (flush_total_times)
9119d9
         *flush_total_times = -1;
9119d9
 
9119d9
-    if (qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name, &stats, 1) != 1)
9119d9
+    if (qemuMonitorJSONGetAllBlockStatsInfo(mon, &blockstats) < 0)
9119d9
         goto cleanup;
9119d9
 
9119d9
-    *rd_req = stats.rd_req;
9119d9
-    *rd_bytes = stats.rd_bytes;
9119d9
-    *wr_req = stats.wr_req;
9119d9
-    *wr_bytes = stats.wr_bytes;
9119d9
+    if (!(stats = virHashLookup(blockstats, dev_name))) {
9119d9
+        virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                       _("cannot find statistics for device '%s'"), dev_name);
9119d9
+        goto cleanup;
9119d9
+    }
9119d9
+
9119d9
+    *rd_req = stats->rd_req;
9119d9
+    *rd_bytes = stats->rd_bytes;
9119d9
+    *wr_req = stats->wr_req;
9119d9
+    *wr_bytes = stats->wr_bytes;
9119d9
     *errs = -1; /* QEMU does not have this */
9119d9
 
9119d9
     if (rd_total_times)
9119d9
-        *rd_total_times = stats.rd_total_times;
9119d9
+        *rd_total_times = stats->rd_total_times;
9119d9
     if (wr_total_times)
9119d9
-        *wr_total_times = stats.wr_total_times;
9119d9
+        *wr_total_times = stats->wr_total_times;
9119d9
     if (flush_req)
9119d9
-        *flush_req = stats.flush_req;
9119d9
+        *flush_req = stats->flush_req;
9119d9
     if (flush_total_times)
9119d9
-        *flush_total_times = stats.flush_total_times;
9119d9
+        *flush_total_times = stats->flush_total_times;
9119d9
 
9119d9
     ret = 0;
9119d9
 
9119d9
  cleanup:
9119d9
+    virHashFree(blockstats);
9119d9
     return ret;
9119d9
 }
9119d9
 
9119d9
 
9119d9
 int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
-                                        const char *dev_name,
9119d9
-                                        qemuBlockStatsPtr bstats,
9119d9
-                                        int nstats)
9119d9
+                                        virHashTablePtr *ret_stats)
9119d9
 {
9119d9
-    int ret, count;
9119d9
+    int ret = -1;
9119d9
+    int rc;
9119d9
     size_t i;
9119d9
-    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
9119d9
-                                                     NULL);
9119d9
+    virJSONValuePtr cmd;
9119d9
     virJSONValuePtr reply = NULL;
9119d9
     virJSONValuePtr devices;
9119d9
+    qemuBlockStatsPtr bstats = NULL;
9119d9
+    virHashTablePtr hash = NULL;
9119d9
 
9119d9
-    if (!cmd)
9119d9
+    if (!(cmd = qemuMonitorJSONMakeCommand("query-blockstats", NULL)))
9119d9
         return -1;
9119d9
 
9119d9
-    if (!bstats || nstats <= 0)
9119d9
-        return -1;
9119d9
+    if (!(hash = virHashCreate(10, virHashValueFree)))
9119d9
+        goto cleanup;
9119d9
 
9119d9
-    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
9119d9
+    if ((rc = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
9119d9
+        goto cleanup;
9119d9
 
9119d9
-    if (ret == 0)
9119d9
-        ret = qemuMonitorJSONCheckError(cmd, reply);
9119d9
-    if (ret < 0)
9119d9
+    if (qemuMonitorJSONCheckError(cmd, reply) < 0)
9119d9
         goto cleanup;
9119d9
-    ret = -1;
9119d9
 
9119d9
     devices = virJSONValueObjectGet(reply, "return");
9119d9
     if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
9119d9
@@ -1781,10 +1787,14 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
         goto cleanup;
9119d9
     }
9119d9
 
9119d9
-    count = 0;
9119d9
-    for (i = 0; i < virJSONValueArraySize(devices) && count < nstats; i++) {
9119d9
+    for (i = 0; i < virJSONValueArraySize(devices); i++) {
9119d9
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
9119d9
         virJSONValuePtr stats;
9119d9
+        const char *devname;
9119d9
+
9119d9
+        if (VIR_ALLOC(bstats) < 0)
9119d9
+            goto cleanup;
9119d9
+
9119d9
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
9119d9
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
                            _("blockstats device entry was not "
9119d9
@@ -1792,29 +1802,16 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
             goto cleanup;
9119d9
         }
9119d9
 
9119d9
-        /* If dev_name is specified, we are looking for a specific device,
9119d9
-         * so we must be stricter.
9119d9
-         */
9119d9
-        if (dev_name) {
9119d9
-            const char *thisdev = virJSONValueObjectGetString(dev, "device");
9119d9
-            if (!thisdev) {
9119d9
-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
-                               _("blockstats device entry was not "
9119d9
-                                 "in expected format"));
9119d9
-                goto cleanup;
9119d9
-            }
9119d9
-
9119d9
-            /* New QEMU has separate names for host & guest side of the disk
9119d9
-             * and libvirt gives the host side a 'drive-' prefix. The passed
9119d9
-             * in dev_name is the guest side though
9119d9
-             */
9119d9
-            if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
9119d9
-                thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
9119d9
-
9119d9
-            if (STRNEQ(thisdev, dev_name))
9119d9
-                continue;
9119d9
+        if (!(devname = virJSONValueObjectGetString(dev, "device"))) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
+                           _("blockstats device entry was not "
9119d9
+                             "in expected format"));
9119d9
+            goto cleanup;
9119d9
         }
9119d9
 
9119d9
+        if (STRPREFIX(devname, QEMU_DRIVE_HOST_PREFIX))
9119d9
+            devname += strlen(QEMU_DRIVE_HOST_PREFIX);
9119d9
+
9119d9
         if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
9119d9
             stats->type != VIR_JSON_TYPE_OBJECT) {
9119d9
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
@@ -1884,22 +1881,18 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
             goto cleanup;
9119d9
         }
9119d9
 
9119d9
-        count++;
9119d9
-        bstats++;
9119d9
-
9119d9
-        if (dev_name && count)
9119d9
-            break;
9119d9
-    }
9119d9
-
9119d9
-    if (dev_name && !count) {
9119d9
-        virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
-                       _("cannot find statistics for device '%s'"), dev_name);
9119d9
-        goto cleanup;
9119d9
+        if (virHashAddEntry(hash, devname, bstats) < 0)
9119d9
+            goto cleanup;
9119d9
+        bstats = NULL;
9119d9
     }
9119d9
 
9119d9
-    ret = count;
9119d9
+    *ret_stats = hash;
9119d9
+    hash = NULL;
9119d9
+    ret = 0;
9119d9
 
9119d9
  cleanup:
9119d9
+    VIR_FREE(bstats);
9119d9
+    virHashFree(hash);
9119d9
     virJSONValueFree(cmd);
9119d9
     virJSONValueFree(reply);
9119d9
     return ret;
9119d9
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
9119d9
index 2402b5a..8e65c4c 100644
9119d9
--- a/src/qemu/qemu_monitor_json.h
9119d9
+++ b/src/qemu/qemu_monitor_json.h
9119d9
@@ -80,9 +80,7 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
9119d9
                                      long long *flush_total_times,
9119d9
                                      long long *errs);
9119d9
 int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
-                                        const char *dev_name,
9119d9
-                                        qemuBlockStatsPtr stats,
9119d9
-                                        int nstats);
9119d9
+                                        virHashTablePtr *ret_stats);
9119d9
 int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
9119d9
                                              int *nparams);
9119d9
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
9119d9
-- 
9119d9
2.1.2
9119d9