9119d9
From 6d5a89f712623c56228aa50e211b58dabf881cc5 Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <6d5a89f712623c56228aa50e211b58dabf881cc5@dist-git>
9119d9
From: Eric Blake <eblake@redhat.com>
9119d9
Date: Wed, 17 Dec 2014 03:09:09 -0700
9119d9
Subject: [PATCH] getstats: crawl backing chain for qemu
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1041569
9119d9
9119d9
Wire up backing chain recursion.  For the first time, it is now
9119d9
possible to get libvirt to expose that qemu tracks read statistics
9119d9
on backing files, as well as report maximum extent written on a
9119d9
backing file during a block-commit operation.
9119d9
9119d9
For a running domain, where one of the two images has a backing
9119d9
file, I see the traditional output:
9119d9
9119d9
$ virsh domstats --block testvm2
9119d9
Domain: 'testvm2'
9119d9
  block.count=2
9119d9
  block.0.name=vda
9119d9
  block.0.path=/tmp/wrapper.qcow2
9119d9
  block.0.rd.reqs=1
9119d9
  block.0.rd.bytes=512
9119d9
  block.0.rd.times=28858
9119d9
  block.0.wr.reqs=0
9119d9
  block.0.wr.bytes=0
9119d9
  block.0.wr.times=0
9119d9
  block.0.fl.reqs=0
9119d9
  block.0.fl.times=0
9119d9
  block.0.allocation=0
9119d9
  block.0.capacity=1310720000
9119d9
  block.0.physical=200704
9119d9
  block.1.name=vdb
9119d9
  block.1.path=/dev/sda7
9119d9
  block.1.rd.reqs=0
9119d9
  block.1.rd.bytes=0
9119d9
  block.1.rd.times=0
9119d9
  block.1.wr.reqs=0
9119d9
  block.1.wr.bytes=0
9119d9
  block.1.wr.times=0
9119d9
  block.1.fl.reqs=0
9119d9
  block.1.fl.times=0
9119d9
  block.1.allocation=0
9119d9
  block.1.capacity=1310720000
9119d9
9119d9
vs. the new output:
9119d9
9119d9
$ virsh domstats --block --backing testvm2
9119d9
Domain: 'testvm2'
9119d9
  block.count=3
9119d9
  block.0.name=vda
9119d9
  block.0.path=/tmp/wrapper.qcow2
9119d9
  block.0.rd.reqs=1
9119d9
  block.0.rd.bytes=512
9119d9
  block.0.rd.times=28858
9119d9
  block.0.wr.reqs=0
9119d9
  block.0.wr.bytes=0
9119d9
  block.0.wr.times=0
9119d9
  block.0.fl.reqs=0
9119d9
  block.0.fl.times=0
9119d9
  block.0.allocation=0
9119d9
  block.0.capacity=1310720000
9119d9
  block.0.physical=200704
9119d9
  block.1.name=vda
9119d9
  block.1.path=/dev/sda6
9119d9
  block.1.backingIndex=1
9119d9
  block.1.rd.reqs=0
9119d9
  block.1.rd.bytes=0
9119d9
  block.1.rd.times=0
9119d9
  block.1.wr.reqs=0
9119d9
  block.1.wr.bytes=0
9119d9
  block.1.wr.times=0
9119d9
  block.1.fl.reqs=0
9119d9
  block.1.fl.times=0
9119d9
  block.1.allocation=327680
9119d9
  block.1.capacity=786432000
9119d9
  block.2.name=vdb
9119d9
  block.2.path=/dev/sda7
9119d9
  block.2.rd.reqs=0
9119d9
  block.2.rd.bytes=0
9119d9
  block.2.rd.times=0
9119d9
  block.2.wr.reqs=0
9119d9
  block.2.wr.bytes=0
9119d9
  block.2.wr.times=0
9119d9
  block.2.fl.reqs=0
9119d9
  block.2.fl.times=0
9119d9
  block.2.allocation=0
9119d9
  block.2.capacity=1310720000
9119d9
9119d9
I may later do a patch that trims the output to avoid 0 stats,
9119d9
particularly for backing files (which are more likely to have
9119d9
0 stats, at least for write statistics when no block-commit
9119d9
is performed).  Also, I still plan to expose physical size
9119d9
information (qemu doesn't expose it yet, so it requires a stat,
9119d9
and for block devices, a further open/seek operation).  But
9119d9
this patch is good enough without worrying about that yet.
9119d9
9119d9
* src/qemu/qemu_driver.c (QEMU_DOMAIN_STATS_BACKING): New internal
9119d9
enum bit.
9119d9
(qemuConnectGetAllDomainStats): Recognize new user flag, and pass
9119d9
details to...
9119d9
(qemuDomainGetStatsBlock): ...here, where we can do longer recursion.
9119d9
(qemuDomainGetStatsOneBlock): Output new field.
9119d9
9119d9
Signed-off-by: Eric Blake <eblake@redhat.com>
9119d9
(cherry picked from commit 3937ef9cf4ff9d6d5aba8b76d9db5e44ae15a2aa)
9119d9
9119d9
Conflicts:
9119d9
	src/qemu/qemu_driver.c
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 src/qemu/qemu_driver.c | 61 ++++++++++++++++++++++++++++++++++++++++----------
9119d9
 1 file changed, 49 insertions(+), 12 deletions(-)
9119d9
9119d9
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
9119d9
index a2535f4..77f8cac 100644
9119d9
--- a/src/qemu/qemu_driver.c
9119d9
+++ b/src/qemu/qemu_driver.c
9119d9
@@ -17732,8 +17732,10 @@ qemuDomainGetStatsState(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
 
9119d9
 
9119d9
 typedef enum {
9119d9
-    QEMU_DOMAIN_STATS_HAVE_JOB = (1 << 0), /* job is entered, monitor can be
9119d9
-                                              accessed */
9119d9
+    QEMU_DOMAIN_STATS_HAVE_JOB = 1 << 0, /* job is entered, monitor can be
9119d9
+                                            accessed */
9119d9
+    QEMU_DOMAIN_STATS_BACKING  = 1 << 1, /* include backing chain in
9119d9
+                                            block stats */
9119d9
 } qemuDomainStatsFlags;
9119d9
 
9119d9
 
9119d9
@@ -17980,6 +17982,19 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
 
9119d9
 #undef QEMU_ADD_NET_PARAM
9119d9
 
9119d9
+#define QEMU_ADD_BLOCK_PARAM_UI(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 (virTypedParamsAddUInt(&(record)->params,                 \
9119d9
+                                  &(record)->nparams,                \
9119d9
+                                  maxparams,                         \
9119d9
+                                  param_name,                        \
9119d9
+                                  value) < 0)                        \
9119d9
+            goto cleanup;                                            \
9119d9
+    } while (0)
9119d9
+
9119d9
 /* expects a LL, but typed parameter must be ULL */
9119d9
 #define QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, num, name, value) \
9119d9
 do { \
9119d9
@@ -18017,20 +18032,27 @@ qemuDomainGetStatsOneBlock(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
                            virDomainDiskDefPtr disk,
9119d9
                            virStorageSourcePtr src,
9119d9
                            size_t block_idx,
9119d9
+                           unsigned int backing_idx,
9119d9
                            bool abbreviated,
9119d9
                            virHashTablePtr stats)
9119d9
 {
9119d9
     qemuBlockStats *entry;
9119d9
     int ret = -1;
9119d9
+    char *alias = NULL;
9119d9
+
9119d9
+    if (disk->info.alias)
9119d9
+        alias = qemuDomainStorageAlias(disk->info.alias, backing_idx);
9119d9
 
9119d9
     QEMU_ADD_NAME_PARAM(record, maxparams, "block", "name", block_idx,
9119d9
                         disk->dst);
9119d9
     if (virStorageSourceIsLocalStorage(src) && src->path)
9119d9
         QEMU_ADD_NAME_PARAM(record, maxparams, "block", "path",
9119d9
                             block_idx, src->path);
9119d9
+    if (backing_idx)
9119d9
+        QEMU_ADD_BLOCK_PARAM_UI(record, maxparams, block_idx, "backingIndex",
9119d9
+                                backing_idx);
9119d9
 
9119d9
-    if (abbreviated || !disk->info.alias ||
9119d9
-        !(entry = virHashLookup(stats, disk->info.alias))) {
9119d9
+    if (abbreviated || !alias || !(entry = virHashLookup(stats, alias))) {
9119d9
         /* FIXME: we could still look up sizing by sharing code
9119d9
          * with qemuDomainGetBlockInfo */
9119d9
         ret = 0;
9119d9
@@ -18066,6 +18088,7 @@ qemuDomainGetStatsOneBlock(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
 
9119d9
     ret = 0;
9119d9
  cleanup:
9119d9
+    VIR_FREE(alias);
9119d9
     return ret;
9119d9
 }
9119d9
 
9119d9
@@ -18084,14 +18107,17 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
     qemuDomainObjPrivatePtr priv = dom->privateData;
9119d9
     bool abbreviated = false;
9119d9
     int count_index = -1;
9119d9
+    size_t visited = 0;
9119d9
+    bool visitBacking = !!(privflags & QEMU_DOMAIN_STATS_BACKING);
9119d9
 
9119d9
     if (!HAVE_JOB(privflags) || !virDomainObjIsActive(dom)) {
9119d9
         abbreviated = true; /* it's ok, just go ahead silently */
9119d9
     } else {
9119d9
         qemuDomainObjEnterMonitor(driver, dom);
9119d9
-        rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats, false);
9119d9
+        rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats,
9119d9
+                                             visitBacking);
9119d9
         ignore_value(qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats,
9119d9
-                                                         false));
9119d9
+                                                         visitBacking));
9119d9
         qemuDomainObjExitMonitor(driver, dom);
9119d9
 
9119d9
         if (rc < 0) {
9119d9
@@ -18108,14 +18134,21 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
9119d9
 
9119d9
     for (i = 0; i < dom->def->ndisks; i++) {
9119d9
         virDomainDiskDefPtr disk = dom->def->disks[i];
9119d9
+        virStorageSourcePtr src = disk->src;
9119d9
+        unsigned int backing_idx = 0;
9119d9
 
9119d9
-        if (qemuDomainGetStatsOneBlock(driver, NULL, dom, record, maxparams,
9119d9
-                                       disk, disk->src, i, abbreviated,
9119d9
-                                       stats) < 0)
9119d9
-            goto cleanup;
9119d9
+        while (src && (backing_idx == 0 || visitBacking)) {
9119d9
+            if (qemuDomainGetStatsOneBlock(driver, NULL, dom, record, maxparams,
9119d9
+                                           disk, src, visited, backing_idx,
9119d9
+                                           abbreviated, stats) < 0)
9119d9
+                goto cleanup;
9119d9
+            visited++;
9119d9
+            backing_idx++;
9119d9
+            src = src->backingStore;
9119d9
+        }
9119d9
     }
9119d9
 
9119d9
-    record->params[count_index].value.ui = i;
9119d9
+    record->params[count_index].value.ui = visited;
9119d9
     ret = 0;
9119d9
 
9119d9
  cleanup:
9119d9
@@ -18258,11 +18291,13 @@ qemuConnectGetAllDomainStats(virConnectPtr conn,
9119d9
     unsigned int domflags = 0;
9119d9
 
9119d9
     if (ndoms)
9119d9
-        virCheckFlags(VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);
9119d9
+        virCheckFlags(VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING |
9119d9
+                      VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);
9119d9
     else
9119d9
         virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
9119d9
                       VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
9119d9
                       VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE |
9119d9
+                      VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING |
9119d9
                       VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);
9119d9
 
9119d9
     if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
9119d9
@@ -18312,6 +18347,8 @@ qemuConnectGetAllDomainStats(virConnectPtr conn,
9119d9
             domflags |= QEMU_DOMAIN_STATS_HAVE_JOB;
9119d9
         /* else: without a job it's still possible to gather some data */
9119d9
 
9119d9
+        if (flags & VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING)
9119d9
+            domflags |= QEMU_DOMAIN_STATS_BACKING;
9119d9
         if (qemuDomainGetStats(conn, dom, stats, &tmp, domflags) < 0)
9119d9
             goto endjob;
9119d9
 
9119d9
-- 
9119d9
2.2.0
9119d9