]> xenbits.xensource.com Git - libvirt.git/commitdiff
getstats: prepare monitor collection for recursion
authorEric Blake <eblake@redhat.com>
Thu, 11 Dec 2014 22:28:41 +0000 (15:28 -0700)
committerEric Blake <eblake@redhat.com>
Tue, 16 Dec 2014 23:08:04 +0000 (16:08 -0700)
A future patch will allow recursion into backing chains when
collecting block stats.  This patch should not change behavior,
but merely moves out the common code that will be reused once
recursion is enabled, and adds the parameter that will turn on
recursion.

* src/qemu/qemu_monitor.h (qemuMonitorGetAllBlockStatsInfo)
(qemuMonitorBlockStatsUpdateCapacity): Add recursion parameter,
although it is ignored for now.
* src/qemu/qemu_monitor.h (qemuMonitorGetAllBlockStatsInfo)
(qemuMonitorBlockStatsUpdateCapacity): Likewise.
* src/qemu/qemu_monitor_json.h
(qemuMonitorJSONGetAllBlockStatsInfo)
(qemuMonitorJSONBlockStatsUpdateCapacity): Likewise.
* src/qemu/qemu_monitor_json.c
(qemuMonitorJSONGetAllBlockStatsInfo)
(qemuMonitorJSONBlockStatsUpdateCapacity): Add parameter, and
split...
(qemuMonitorJSONGetOneBlockStatsInfo)
(qemuMonitorJSONBlockStatsUpdateCapacityOne): ...into helpers.
(qemuMonitorJSONGetBlockStatsInfo): Update caller.
* src/qemu/qemu_driver.c (qemuDomainGetStatsBlock): Update caller.
* src/qemu/qemu_migration.c (qemuMigrationCookieAddNBD): Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h

index f0d7af70df05c098a472e7a81046db7c77449eb0..75ea218b47e3b8a58be9544686de4e9ce87549d0 100644 (file)
@@ -18552,8 +18552,9 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
         abbreviated = true; /* it's ok, just go ahead silently */
     } else {
         qemuDomainObjEnterMonitor(driver, dom);
-        rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats);
-        ignore_value(qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats));
+        rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats, false);
+        ignore_value(qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats,
+                                                         false));
         qemuDomainObjExitMonitor(driver, dom);
 
         if (rc < 0) {
index 0acbb5795e930e27157c580a3236701acd91bbaf..834093df291759544e703c14c55e8f896f513308 100644 (file)
@@ -571,7 +571,8 @@ qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig,
                 goto cleanup;
 
             qemuDomainObjEnterMonitor(driver, vm);
-            if (qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats) < 0) {
+            if (qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats,
+                                                    false) < 0) {
                 qemuDomainObjExitMonitor(driver, vm);
                 goto cleanup;
             }
index c9c84f9d776935e07ad9a944346217ecc7183856..100bbd0175cfa6685ac7fa76a9c495764451e8f9 100644 (file)
@@ -1783,16 +1783,16 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
     return ret;
 }
 
-/* Fills the first 'nstats' block stats. 'stats' must be an array.
- * Returns <0 on error, otherwise the number of block stats retrieved.
- * if 'dev_name' is != NULL, look for this device only and skip
- * any other. In that case return value cannot be greater than 1.
+
+/* Creates a hash table in 'ret_stats' with all block stats.
+ * Returns <0 on error, 0 on success.
  */
 int
 qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
-                                virHashTablePtr *ret_stats)
+                                virHashTablePtr *ret_stats,
+                                bool backingChain)
 {
-    VIR_DEBUG("mon=%p ret_stats=%p", mon, ret_stats);
+    VIR_DEBUG("mon=%p ret_stats=%p, backing=%d", mon, ret_stats, backingChain);
 
     if (!mon->json) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1800,15 +1800,17 @@ qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
         return -1;
     }
 
-    return qemuMonitorJSONGetAllBlockStatsInfo(mon, ret_stats);
+    return qemuMonitorJSONGetAllBlockStatsInfo(mon, ret_stats, backingChain);
 }
 
 
 /* Updates "stats" to fill virtual and physical size of the image */
-int qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
-                                        virHashTablePtr stats)
+int
+qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
+                                    virHashTablePtr stats,
+                                    bool backingChain)
 {
-    VIR_DEBUG("mon=%p, stats=%p", mon, stats);
+    VIR_DEBUG("mon=%p, stats=%p, backing=%d", mon, stats, backingChain);
 
     if (!mon->json) {
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
@@ -1816,7 +1818,7 @@ int qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
         return -1;
     }
 
-    return qemuMonitorJSONBlockStatsUpdateCapacity(mon, stats);
+    return qemuMonitorJSONBlockStatsUpdateCapacity(mon, stats, backingChain);
 }
 
 
index 21533a4c81dbd07c54d818222da59cb4f2fbe999..edab66f8cb7ca41f61c832b91c213584ab2e949b 100644 (file)
@@ -382,11 +382,13 @@ struct _qemuBlockStats {
 };
 
 int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
-                                    virHashTablePtr *ret_stats)
+                                    virHashTablePtr *ret_stats,
+                                    bool backingChain)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
-                                        virHashTablePtr stats)
+                                        virHashTablePtr stats,
+                                        bool backingChain)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
index 162579bfd44b0bd0d588347765fae6e069902acf..3a13890828dbb058b18ebd33da63c15520439316 100644 (file)
@@ -1627,7 +1627,7 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
     if (flush_total_times)
         *flush_total_times = -1;
 
-    if (qemuMonitorJSONGetAllBlockStatsInfo(mon, &blockstats) < 0)
+    if (qemuMonitorJSONGetAllBlockStatsInfo(mon, &blockstats, false) < 0)
         goto cleanup;
 
     if (!(stats = virHashLookup(blockstats, dev_name))) {
@@ -1693,8 +1693,105 @@ qemuMonitorJSONDevGetBlockExtent(virJSONValuePtr dev,
 }
 
 
-int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
-                                        virHashTablePtr *ret_stats)
+static int
+qemuMonitorJSONGetOneBlockStatsInfo(virJSONValuePtr dev,
+                                    const char *dev_name,
+                                    virHashTablePtr hash,
+                                    bool backingChain ATTRIBUTE_UNUSED)
+{
+    qemuBlockStatsPtr bstats = NULL;
+    virJSONValuePtr stats;
+    int ret = -1;
+
+    if (VIR_ALLOC(bstats) < 0)
+        goto cleanup;
+
+    if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
+        stats->type != VIR_JSON_TYPE_OBJECT) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("blockstats stats entry was not "
+                         "in expected format"));
+        goto cleanup;
+    }
+
+    if (virJSONValueObjectGetNumberLong(stats, "rd_bytes",
+                                        &bstats->rd_bytes) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "rd_bytes");
+        goto cleanup;
+    }
+    if (virJSONValueObjectGetNumberLong(stats, "rd_operations",
+                                        &bstats->rd_req) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "rd_operations");
+        goto cleanup;
+    }
+    if (virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
+        (virJSONValueObjectGetNumberLong(stats, "rd_total_time_ns",
+                                         &bstats->rd_total_times) < 0)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "rd_total_time_ns");
+        goto cleanup;
+    }
+    if (virJSONValueObjectGetNumberLong(stats, "wr_bytes",
+                                        &bstats->wr_bytes) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "wr_bytes");
+        goto cleanup;
+    }
+    if (virJSONValueObjectGetNumberLong(stats, "wr_operations",
+                                        &bstats->wr_req) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "wr_operations");
+        goto cleanup;
+    }
+    if (virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
+        (virJSONValueObjectGetNumberLong(stats, "wr_total_time_ns",
+                                         &bstats->wr_total_times) < 0)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "wr_total_time_ns");
+        goto cleanup;
+    }
+    if (virJSONValueObjectHasKey(stats, "flush_operations") &&
+        (virJSONValueObjectGetNumberLong(stats, "flush_operations",
+                                         &bstats->flush_req) < 0)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "flush_operations");
+        goto cleanup;
+    }
+    if (virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
+        (virJSONValueObjectGetNumberLong(stats, "flush_total_time_ns",
+                                         &bstats->flush_total_times) < 0)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("cannot read %s statistic"),
+                       "flush_total_time_ns");
+        goto cleanup;
+    }
+
+    /* it's ok to not have this information here. Just skip silently. */
+    qemuMonitorJSONDevGetBlockExtent(dev, &bstats->wr_highest_offset);
+
+    if (virHashAddEntry(hash, dev_name, bstats) < 0)
+        goto cleanup;
+    bstats = NULL;
+    ret = 0;
+ cleanup:
+    VIR_FREE(bstats);
+    return ret;
+}
+
+
+int
+qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
+                                    virHashTablePtr *ret_stats,
+                                    bool backingChain)
 {
     int ret = -1;
     int rc;
@@ -1702,7 +1799,6 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
     virJSONValuePtr cmd;
     virJSONValuePtr reply = NULL;
     virJSONValuePtr devices;
-    qemuBlockStatsPtr bstats = NULL;
     virHashTablePtr hash = NULL;
 
     if (!(cmd = qemuMonitorJSONMakeCommand("query-blockstats", NULL)))
@@ -1726,12 +1822,8 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
 
     for (i = 0; i < virJSONValueArraySize(devices); i++) {
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
-        virJSONValuePtr stats;
         const char *dev_name;
 
-        if (VIR_ALLOC(bstats) < 0)
-            goto cleanup;
-
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("blockstats device entry was not "
@@ -1749,81 +1841,10 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
         if (STRPREFIX(dev_name, QEMU_DRIVE_HOST_PREFIX))
             dev_name += strlen(QEMU_DRIVE_HOST_PREFIX);
 
-        if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
-            stats->type != VIR_JSON_TYPE_OBJECT) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("blockstats stats entry was not "
-                             "in expected format"));
-            goto cleanup;
-        }
-
-        if (virJSONValueObjectGetNumberLong(stats, "rd_bytes",
-                                            &bstats->rd_bytes) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "rd_bytes");
-            goto cleanup;
-        }
-        if (virJSONValueObjectGetNumberLong(stats, "rd_operations",
-                                            &bstats->rd_req) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                            "rd_operations");
-            goto cleanup;
-        }
-        if (virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
-            (virJSONValueObjectGetNumberLong(stats, "rd_total_time_ns",
-                                             &bstats->rd_total_times) < 0)) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "rd_total_time_ns");
-            goto cleanup;
-        }
-        if (virJSONValueObjectGetNumberLong(stats, "wr_bytes",
-                                            &bstats->wr_bytes) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "wr_bytes");
+        if (qemuMonitorJSONGetOneBlockStatsInfo(dev, dev_name, hash,
+                                                backingChain) < 0)
             goto cleanup;
-        }
-        if (virJSONValueObjectGetNumberLong(stats, "wr_operations",
-                                            &bstats->wr_req) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "wr_operations");
-            goto cleanup;
-        }
-        if (virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
-            (virJSONValueObjectGetNumberLong(stats, "wr_total_time_ns",
-                                             &bstats->wr_total_times) < 0)) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "wr_total_time_ns");
-            goto cleanup;
-        }
-        if (virJSONValueObjectHasKey(stats, "flush_operations") &&
-            (virJSONValueObjectGetNumberLong(stats, "flush_operations",
-                                             &bstats->flush_req) < 0)) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "flush_operations");
-            goto cleanup;
-        }
-        if (virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
-            (virJSONValueObjectGetNumberLong(stats, "flush_total_time_ns",
-                                             &bstats->flush_total_times) < 0)) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("cannot read %s statistic"),
-                           "flush_total_time_ns");
-            goto cleanup;
-        }
-
-        /* it's ok to not have this information here. Just skip silently. */
-        qemuMonitorJSONDevGetBlockExtent(dev, &bstats->wr_highest_offset);
 
-        if (virHashAddEntry(hash, dev_name, bstats) < 0)
-            goto cleanup;
-        bstats = NULL;
     }
 
     *ret_stats = hash;
@@ -1831,7 +1852,6 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
     ret = 0;
 
  cleanup:
-    VIR_FREE(bstats);
     virHashFree(hash);
     virJSONValueFree(cmd);
     virJSONValueFree(reply);
@@ -1839,8 +1859,45 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
 }
 
 
-int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
-                                            virHashTablePtr stats)
+static int
+qemuMonitorJSONBlockStatsUpdateCapacityOne(virJSONValuePtr image,
+                                           const char *dev_name,
+                                           virHashTablePtr stats,
+                                           bool backingChain ATTRIBUTE_UNUSED)
+{
+    qemuBlockStatsPtr bstats;
+    int ret = -1;
+
+    if (!(bstats = virHashLookup(stats, dev_name))) {
+        if (VIR_ALLOC(bstats) < 0)
+            goto cleanup;
+
+        if (virHashAddEntry(stats, dev_name, bstats) < 0) {
+            VIR_FREE(bstats);
+            goto cleanup;
+        }
+    }
+
+    /* After this point, we ignore failures; the stats were
+     * zero-initialized when created which is a sane fallback.  */
+    ret = 0;
+    if (virJSONValueObjectGetNumberUlong(image, "virtual-size",
+                                         &bstats->capacity) < 0)
+        goto cleanup;
+
+    /* if actual-size is missing, image is not thin provisioned */
+    if (virJSONValueObjectGetNumberUlong(image, "actual-size",
+                                         &bstats->physical) < 0)
+        bstats->physical = bstats->capacity;
+ cleanup:
+    return ret;
+}
+
+
+int
+qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
+                                        virHashTablePtr stats,
+                                        bool backingChain)
 {
     int ret = -1;
     int rc;
@@ -1869,7 +1926,6 @@ int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
         virJSONValuePtr inserted;
         virJSONValuePtr image;
-        qemuBlockStatsPtr bstats;
         const char *dev_name;
 
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
@@ -1894,24 +1950,9 @@ int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
             !(image = virJSONValueObjectGet(inserted, "image")))
             continue;
 
-        if (!(bstats = virHashLookup(stats, dev_name))) {
-            if (VIR_ALLOC(bstats) < 0)
-                goto cleanup;
-
-            if (virHashAddEntry(stats, dev_name, bstats) < 0) {
-                VIR_FREE(bstats);
-                goto cleanup;
-            }
-        }
-
-        if (virJSONValueObjectGetNumberUlong(image, "virtual-size",
-                                             &bstats->capacity) < 0)
-            continue;
-
-        /* if actual-size is missing, image is not thin provisioned */
-        if (virJSONValueObjectGetNumberUlong(image, "actual-size",
-                                             &bstats->physical) < 0)
-            bstats->physical = bstats->capacity;
+        if (qemuMonitorJSONBlockStatsUpdateCapacityOne(image, dev_name, stats,
+                                                       backingChain) < 0)
+            goto cleanup;
     }
 
     ret = 0;
index ae20fb1d2ca0bdc20331ecb549420c6ad850805f..222f11ee085a13332e1df2405b3dfb164ecec2c7 100644 (file)
@@ -80,9 +80,11 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      long long *flush_total_times,
                                      long long *errs);
 int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
-                                        virHashTablePtr *ret_stats);
+                                        virHashTablePtr *ret_stats,
+                                        bool backingChain);
 int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
-                                            virHashTablePtr stats);
+                                            virHashTablePtr stats,
+                                            bool backingChain);
 int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
                                              int *nparams);
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,