9119d9
From bcdc18a163fe888c98eda477eb265541ed12357a Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <bcdc18a163fe888c98eda477eb265541ed12357a@dist-git>
9119d9
From: Francesco Romani <fromani@redhat.com>
9119d9
Date: Wed, 1 Oct 2014 11:20:24 +0200
9119d9
Subject: [PATCH] qemu: bulk stats: add block allocation information
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1113116
9119d9
9119d9
Management software wants to be able to allocate disk space on demand.
9119d9
To support this they need keep track of the space occupation of the
9119d9
block device.  This information is reported by qemu as part of block
9119d9
stats.
9119d9
9119d9
This patch extend the block information in the bulk stats with the
9119d9
allocation information.
9119d9
9119d9
To keep the same behaviour a helper is extracted from
9119d9
qemuMonitorJSONGetBlockExtent in order to get per-device allocation
9119d9
information.
9119d9
9119d9
Signed-off-by: Francesco Romani <fromani@redhat.com>
9119d9
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
9119d9
(cherry picked from commit 7557ddf8be79f9687bc8f69946aba71c4c29d7d5)
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 src/libvirt.c                |  6 +++
9119d9
 src/qemu/qemu_driver.c       | 27 +++++++++++++
9119d9
 src/qemu/qemu_monitor.h      |  1 +
9119d9
 src/qemu/qemu_monitor_json.c | 91 ++++++++++++++++++++++++++++++++++----------
9119d9
 4 files changed, 105 insertions(+), 20 deletions(-)
9119d9
9119d9
diff --git a/src/libvirt.c b/src/libvirt.c
9119d9
index af89aa2..5c086c8 100644
9119d9
--- a/src/libvirt.c
9119d9
+++ b/src/libvirt.c
9119d9
@@ -21615,6 +21615,12 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
9119d9
  *                          unsigned long long.
9119d9
  * "block.<num>.errors" - Xen only: the 'oo_req' value as
9119d9
  *                        unsigned long long.
9119d9
+ * "block.<num>.allocation" - offset of the highest written sector
9119d9
+ *                            as unsigned long long.
9119d9
+ * "block.<num>.capacity" - logical size in bytes of the block device backing
9119d9
+ *                          image as unsigned long long.
9119d9
+ * "block.<num>.physical" - physical size in bytes of the container of the
9119d9
+ *                          backing image as unsigned long long.
9119d9
  *
9119d9
  * Note that entire stats groups or individual stat fields may be missing from
9119d9
  * the output in case they are not supported by the given hypervisor, are not
9119d9
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
9119d9
index 1a16da7..9586c43 100644
9119d9
--- a/src/qemu/qemu_driver.c
9119d9
+++ b/src/qemu/qemu_driver.c
9119d9
@@ -17705,6 +17705,19 @@ do { \
9119d9
         goto cleanup; \
9119d9
 } while (0)
9119d9
 
9119d9
+#define QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, num, name, value) \
9119d9
+do { \
9119d9
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
9119d9
+    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
9119d9
+             "block.%zu.%s", num, name); \
9119d9
+    if (virTypedParamsAddULLong(&(record)->params, \
9119d9
+                                &(record)->nparams, \
9119d9
+                                maxparams, \
9119d9
+                                param_name, \
9119d9
+                                value) < 0) \
9119d9
+        goto cleanup; \
9119d9
+} while (0)
9119d9
+
9119d9
 static int
9119d9
 qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
                         virDomainObjPtr dom,
9119d9
@@ -17723,6 +17736,7 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
 
9119d9
     qemuDomainObjEnterMonitor(driver, dom);
9119d9
     rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats);
9119d9
+    ignore_value(qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats));
9119d9
     qemuDomainObjExitMonitor(driver, dom);
9119d9
 
9119d9
     if (rc < 0) {
9119d9
@@ -17759,6 +17773,17 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
                                 "fl.reqs", entry->flush_req);
9119d9
         QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
9119d9
                                 "fl.times", entry->flush_total_times);
9119d9
+
9119d9
+        QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
9119d9
+                                 "allocation", entry->wr_highest_offset);
9119d9
+
9119d9
+        if (entry->capacity)
9119d9
+            QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
9119d9
+                                     "capacity", entry->capacity);
9119d9
+        if (entry->physical)
9119d9
+            QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
9119d9
+                                     "physical", entry->physical);
9119d9
+
9119d9
     }
9119d9
 
9119d9
     ret = 0;
9119d9
@@ -17770,6 +17795,8 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
 
9119d9
 #undef QEMU_ADD_BLOCK_PARAM_LL
9119d9
 
9119d9
+#undef QEMU_ADD_BLOCK_PARAM_ULL
9119d9
+
9119d9
 #undef QEMU_ADD_NAME_PARAM
9119d9
 
9119d9
 #undef QEMU_ADD_COUNT_PARAM
9119d9
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
9119d9
index 9c798cf..5bffca8 100644
9119d9
--- a/src/qemu/qemu_monitor.h
9119d9
+++ b/src/qemu/qemu_monitor.h
9119d9
@@ -360,6 +360,7 @@ struct _qemuBlockStats {
9119d9
     long long flush_total_times;
9119d9
     unsigned long long capacity;
9119d9
     unsigned long long physical;
9119d9
+    unsigned long long wr_highest_offset;
9119d9
 };
9119d9
 
9119d9
 int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
9119d9
index b0a9c99..afb713d 100644
9119d9
--- a/src/qemu/qemu_monitor_json.c
9119d9
+++ b/src/qemu/qemu_monitor_json.c
9119d9
@@ -1756,6 +1756,40 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
9119d9
 }
9119d9
 
9119d9
 
9119d9
+typedef enum {
9119d9
+    QEMU_MONITOR_BLOCK_EXTENT_ERROR_OK,
9119d9
+    QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOPARENT,
9119d9
+    QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOSTATS,
9119d9
+    QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOOFFSET,
9119d9
+} qemuMonitorBlockExtentError;
9119d9
+
9119d9
+
9119d9
+static int
9119d9
+qemuMonitorJSONDevGetBlockExtent(virJSONValuePtr dev,
9119d9
+                                 unsigned long long *extent)
9119d9
+{
9119d9
+    virJSONValuePtr stats;
9119d9
+    virJSONValuePtr parent;
9119d9
+
9119d9
+    if ((parent = virJSONValueObjectGet(dev, "parent")) == NULL ||
9119d9
+        parent->type != VIR_JSON_TYPE_OBJECT) {
9119d9
+        return QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOPARENT;
9119d9
+    }
9119d9
+
9119d9
+    if ((stats = virJSONValueObjectGet(parent, "stats")) == NULL ||
9119d9
+        stats->type != VIR_JSON_TYPE_OBJECT) {
9119d9
+        return QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOSTATS;
9119d9
+    }
9119d9
+
9119d9
+    if (virJSONValueObjectGetNumberUlong(stats, "wr_highest_offset",
9119d9
+                                         extent) < 0) {
9119d9
+        return QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOOFFSET;
9119d9
+    }
9119d9
+
9119d9
+    return QEMU_MONITOR_BLOCK_EXTENT_ERROR_OK;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
                                         virHashTablePtr *ret_stats)
9119d9
 {
9119d9
@@ -1881,6 +1915,9 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
9119d9
             goto cleanup;
9119d9
         }
9119d9
 
9119d9
+        /* it's ok to not have this information here. Just skip silently. */
9119d9
+        qemuMonitorJSONDevGetBlockExtent(dev, &bstats->wr_highest_offset);
9119d9
+
9119d9
         if (virHashAddEntry(hash, dev_name, bstats) < 0)
9119d9
             goto cleanup;
9119d9
         bstats = NULL;
9119d9
@@ -2050,6 +2087,36 @@ int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
9119d9
     return ret;
9119d9
 }
9119d9
 
9119d9
+
9119d9
+static int
9119d9
+qemuMonitorJSONReportBlockExtentError(qemuMonitorBlockExtentError error)
9119d9
+{
9119d9
+    switch (error) {
9119d9
+    case QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOPARENT:
9119d9
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
+                       _("blockstats parent entry was not in "
9119d9
+                         "expected format"));
9119d9
+        break;
9119d9
+
9119d9
+    case QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOSTATS:
9119d9
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
+                       _("blockstats stats entry was not in "
9119d9
+                         "expected format"));
9119d9
+
9119d9
+    case QEMU_MONITOR_BLOCK_EXTENT_ERROR_NOOFFSET:
9119d9
+        virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                       _("cannot read %s statistic"),
9119d9
+                         "wr_highest_offset");
9119d9
+        break;
9119d9
+
9119d9
+    case QEMU_MONITOR_BLOCK_EXTENT_ERROR_OK:
9119d9
+        return 0;
9119d9
+    }
9119d9
+
9119d9
+    return -1;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
9119d9
                                   const char *dev_name,
9119d9
                                   unsigned long long *extent)
9119d9
@@ -2084,9 +2151,8 @@ int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
9119d9
 
9119d9
     for (i = 0; i < virJSONValueArraySize(devices); i++) {
9119d9
         virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
9119d9
-        virJSONValuePtr stats;
9119d9
-        virJSONValuePtr parent;
9119d9
         const char *thisdev;
9119d9
+        int err;
9119d9
         if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
9119d9
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
                            _("blockstats device entry was not in expected format"));
9119d9
@@ -2110,24 +2176,9 @@ int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
9119d9
             continue;
9119d9
 
9119d9
         found = true;
9119d9
-        if ((parent = virJSONValueObjectGet(dev, "parent")) == NULL ||
9119d9
-            parent->type != VIR_JSON_TYPE_OBJECT) {
9119d9
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
-                           _("blockstats parent entry was not in expected format"));
9119d9
-            goto cleanup;
9119d9
-        }
9119d9
-
9119d9
-        if ((stats = virJSONValueObjectGet(parent, "stats")) == NULL ||
9119d9
-            stats->type != VIR_JSON_TYPE_OBJECT) {
9119d9
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9119d9
-                           _("blockstats stats entry was not in expected format"));
9119d9
-            goto cleanup;
9119d9
-        }
9119d9
-
9119d9
-        if (virJSONValueObjectGetNumberUlong(stats, "wr_highest_offset", extent) < 0) {
9119d9
-            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
-                           _("cannot read %s statistic"),
9119d9
-                           "wr_highest_offset");
9119d9
+        if ((err = qemuMonitorJSONDevGetBlockExtent(dev, extent)) !=
9119d9
+             QEMU_MONITOR_BLOCK_EXTENT_ERROR_OK) {
9119d9
+            qemuMonitorJSONReportBlockExtentError(err);
9119d9
             goto cleanup;
9119d9
         }
9119d9
     }
9119d9
-- 
9119d9
2.1.2
9119d9