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