|
|
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 |
|