[libvirt] [PATCHv2 03/11] qemu: add helper to get the block stats

Francesco Romani fromani at redhat.com
Tue Sep 2 12:31:49 UTC 2014


Add an helper function to get the block stats
of a disk.
This helper is meant to be used by the bulk stats API.

Signed-off-by: Francesco Romani <fromani at redhat.com>
---
 src/qemu/qemu_driver.c       |  41 +++++++++++++++
 src/qemu/qemu_monitor.c      |  23 +++++++++
 src/qemu/qemu_monitor.h      |  18 +++++++
 src/qemu/qemu_monitor_json.c | 118 +++++++++++++++++++++++++++++--------------
 src/qemu/qemu_monitor_json.h |   4 ++
 5 files changed, 165 insertions(+), 39 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1842e60..39e2c1b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -178,6 +178,12 @@ static int qemuDomainHelperGetVcpus(virDomainObjPtr vm,
                                     unsigned char *cpumaps,
                                     int maplen);
 
+static int qemuDomainGetBlockStats(virQEMUDriverPtr driver,
+                                   virDomainObjPtr vm,
+                                   struct qemuBlockStats *stats,
+                                   int nstats);
+
+
 virQEMUDriverPtr qemu_driver = NULL;
 
 
@@ -9672,6 +9678,41 @@ qemuDomainBlockStats(virDomainPtr dom,
     return ret;
 }
 
+
+/*
+ * returns at most the first `nstats' stats, then stops.
+ * Returns the number of stats filled.
+ */
+static int
+qemuDomainGetBlockStats(virQEMUDriverPtr driver,
+                        virDomainObjPtr vm,
+                        struct qemuBlockStats *stats,
+                        int nstats)
+{
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv;
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+        goto cleanup;
+
+    priv = vm->privateData;
+
+    qemuDomainObjEnterMonitor(driver, vm);
+
+    ret = qemuMonitorGetAllBlockStatsInfo(priv->mon, NULL,
+                                          stats, nstats);
+
+    qemuDomainObjExitMonitor(driver, vm);
+
+    if (!qemuDomainObjEndJob(driver, vm))
+        vm = NULL;
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
 static int
 qemuDomainBlockStatsFlags(virDomainPtr dom,
                           const char *path,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5b2952a..8aadba5 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1754,6 +1754,29 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
     return ret;
 }
 
+int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
+                                    const char *dev_name,
+                                    struct qemuBlockStats *stats,
+                                    int nstats)
+{
+    int ret;
+    VIR_DEBUG("mon=%p dev=%s", mon, dev_name);
+
+    if (!mon) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("monitor must not be NULL"));
+        return -1;
+    }
+
+    if (mon->json)
+        ret = qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name,
+                                                  stats, nstats);
+    else
+        ret = -1; /* not supported */
+
+    return ret;
+}
+
 /* Return 0 and update @nparams with the number of block stats
  * QEMU supports if success. Return -1 if failure.
  */
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4fd6f01..1b7d00b 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -346,6 +346,24 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  long long *flush_req,
                                  long long *flush_total_times,
                                  long long *errs);
+
+struct qemuBlockStats {
+    long long rd_req;
+    long long rd_bytes;
+    long long wr_req;
+    long long wr_bytes;
+    long long rd_total_times;
+    long long wr_total_times;
+    long long flush_req;
+    long long flush_total_times;
+    long long errs; /* meaningless for QEMU */
+};
+
+int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
+                                    const char *dev_name,
+                                    struct qemuBlockStats *stats,
+                                    int nstats);
+
 int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
                                          int *nparams);
 
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 62e7d5d..68c5cf8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1712,13 +1712,9 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      long long *flush_total_times,
                                      long long *errs)
 {
-    int ret;
-    size_t i;
-    bool found = false;
-    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
-                                                     NULL);
-    virJSONValuePtr reply = NULL;
-    virJSONValuePtr devices;
+    struct qemuBlockStats stats;
+    int nstats = 1;
+    int ret = -1;
 
     *rd_req = *rd_bytes = -1;
     *wr_req = *wr_bytes = *errs = -1;
@@ -1732,9 +1728,45 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
     if (flush_total_times)
         *flush_total_times = -1;
 
+    if (qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name, &stats, nstats) != nstats)
+        goto cleanup;
+
+    *rd_req = stats.rd_req;
+    *rd_bytes = stats.rd_bytes;
+    *rd_total_times = stats.rd_total_times;
+    *wr_req = stats.wr_req;
+    *wr_bytes = stats.wr_bytes;
+    *wr_total_times = stats.wr_total_times;
+    *flush_req = stats.flush_req;
+    *flush_total_times = stats.flush_total_times;
+    *errs = stats.errs;
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+
+int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
+                                        const char *dev_name,
+                                        struct qemuBlockStats *blockstats,
+                                        int nstats)
+{
+    int ret;
+    size_t i;
+    bool found = false;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr devices;
+
     if (!cmd)
         return -1;
 
+    if (!blockstats || nstats <= 0)
+        return -1;
+
     ret = qemuMonitorJSONCommand(mon, cmd, &reply);
 
     if (ret == 0)
@@ -1750,33 +1782,41 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
         goto cleanup;
     }
 
+    ret = 0;
     for (i = 0; i < virJSONValueArraySize(devices); i++) {
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
         virJSONValuePtr stats;
-        const char *thisdev;
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("blockstats device entry was not in expected format"));
             goto cleanup;
         }
 
-        if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("blockstats device entry was not in expected format"));
-            goto cleanup;
+        if (ret > nstats) {
+            break;
         }
 
-        /* New QEMU has separate names for host & guest side of the disk
-         * and libvirt gives the host side a 'drive-' prefix. The passed
-         * in dev_name is the guest side though
-         */
-        if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
-            thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
+        if (dev_name != NULL) {
+            const char *thisdev;
+            if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("blockstats device entry was not in expected format"));
+                goto cleanup;
+            }
 
-        if (STRNEQ(thisdev, dev_name))
-            continue;
+            /* New QEMU has separate names for host & guest side of the disk
+             * and libvirt gives the host side a 'drive-' prefix. The passed
+             * in dev_name is the guest side though
+             */
+            if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
+                thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+            if (STRNEQ(thisdev, dev_name))
+                continue;
+
+            found = true;
+        }
 
-        found = true;
         if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
             stats->type != VIR_JSON_TYPE_OBJECT) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1784,74 +1824,74 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
             goto cleanup;
         }
 
-        if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", rd_bytes) < 0) {
+        if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", &blockstats->rd_bytes) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "rd_bytes");
             goto cleanup;
         }
-        if (virJSONValueObjectGetNumberLong(stats, "rd_operations", rd_req) < 0) {
+        if (virJSONValueObjectGetNumberLong(stats, "rd_operations", &blockstats->rd_req) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                             "rd_operations");
             goto cleanup;
         }
-        if (rd_total_times &&
-            virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
+        if (virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
             (virJSONValueObjectGetNumberLong(stats, "rd_total_time_ns",
-                                             rd_total_times) < 0)) {
+                                             &blockstats->rd_total_times) < 0)) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "rd_total_time_ns");
             goto cleanup;
         }
-        if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", wr_bytes) < 0) {
+        if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", &blockstats->wr_bytes) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "wr_bytes");
             goto cleanup;
         }
-        if (virJSONValueObjectGetNumberLong(stats, "wr_operations", wr_req) < 0) {
+        if (virJSONValueObjectGetNumberLong(stats, "wr_operations", &blockstats->wr_req) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "wr_operations");
             goto cleanup;
         }
-        if (wr_total_times &&
-            virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
+        if (virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
             (virJSONValueObjectGetNumberLong(stats, "wr_total_time_ns",
-                                             wr_total_times) < 0)) {
+                                             &blockstats->wr_total_times) < 0)) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "wr_total_time_ns");
             goto cleanup;
         }
-        if (flush_req &&
-            virJSONValueObjectHasKey(stats, "flush_operations") &&
+        if (virJSONValueObjectHasKey(stats, "flush_operations") &&
             (virJSONValueObjectGetNumberLong(stats, "flush_operations",
-                                            flush_req) < 0)) {
+                                            &blockstats->flush_req) < 0)) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "flush_operations");
             goto cleanup;
         }
-        if (flush_total_times &&
-            virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
+        if (virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
             (virJSONValueObjectGetNumberLong(stats, "flush_total_time_ns",
-                                            flush_total_times) < 0)) {
+                                            &blockstats->flush_total_times) < 0)) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot read %s statistic"),
                            "flush_total_time_ns");
             goto cleanup;
         }
+        blockstats->errs = -1; /* meaningless for QEMU */
+
+        ret++;
+        blockstats++;
     }
 
-    if (!found) {
+    if (dev_name != NULL && !found) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find statistics for device '%s'"), dev_name);
+        ret = 0;
         goto cleanup;
     }
-    ret = 0;
 
  cleanup:
     virJSONValueFree(cmd);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index d8c9308..79058c1 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -79,6 +79,10 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      long long *flush_req,
                                      long long *flush_total_times,
                                      long long *errs);
+int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
+                                        const char *dev_name,
+                                        struct qemuBlockStats *stats,
+                                        int nstats);
 int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
                                              int *nparams);
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
-- 
1.9.3




More information about the libvir-list mailing list