Add an helper function to get the block stats
of a disk.
This helper is meant to be used by the bulk stats API.
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
src/qemu/qemu_driver.c | 41 +++++++++++++++
src/qemu/qemu_monitor.c | 23 +++++++++
src/qemu/qemu_monitor.h | 18 +++++++
src/qemu/qemu_monitor_json.c | 118 +++++++++++++++++++++++++++++--------------
src/qemu/qemu_monitor_json.h | 4 ++
5 files changed, 165 insertions(+), 39 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1842e60..39e2c1b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -178,6 +178,12 @@ static int qemuDomainHelperGetVcpus(virDomainObjPtr vm,
unsigned char *cpumaps,
int maplen);
+static int qemuDomainGetBlockStats(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ struct qemuBlockStats *stats,
+ int nstats);
+
+
virQEMUDriverPtr qemu_driver = NULL;
@@ -9672,6 +9678,41 @@ qemuDomainBlockStats(virDomainPtr dom,
return ret;
}
+
+/*
+ * returns at most the first `nstats' stats, then stops.
+ * Returns the number of stats filled.
+ */
+static int
+qemuDomainGetBlockStats(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ struct qemuBlockStats *stats,
+ int nstats)
+{
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv;
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+ goto cleanup;
+
+ priv = vm->privateData;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ ret = qemuMonitorGetAllBlockStatsInfo(priv->mon, NULL,
+ stats, nstats);
+
+ qemuDomainObjExitMonitor(driver, vm);
+
+ if (!qemuDomainObjEndJob(driver, vm))
+ vm = NULL;
+
+ cleanup:
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+
static int
qemuDomainBlockStatsFlags(virDomainPtr dom,
const char *path,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5b2952a..8aadba5 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1754,6 +1754,29 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
+ const char *dev_name,
+ struct qemuBlockStats *stats,
+ int nstats)
+{
+ int ret;
+ VIR_DEBUG("mon=%p dev=%s", mon, dev_name);
+
+ if (!mon) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name,
+ stats, nstats);
+ else
+ ret = -1; /* not supported */
+
+ return ret;
+}
+
/* Return 0 and update @nparams with the number of block stats
* QEMU supports if success. Return -1 if failure.
*/
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4fd6f01..1b7d00b 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -346,6 +346,24 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
long long *flush_req,
long long *flush_total_times,
long long *errs);
+
+struct qemuBlockStats {
+ long long rd_req;
+ long long rd_bytes;
+ long long wr_req;
+ long long wr_bytes;
+ long long rd_total_times;
+ long long wr_total_times;
+ long long flush_req;
+ long long flush_total_times;
+ long long errs; /* meaningless for QEMU */
+};
+
+int qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
+ const char *dev_name,
+ struct qemuBlockStats *stats,
+ int nstats);
+
int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
int *nparams);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 62e7d5d..68c5cf8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1712,13 +1712,9 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
long long *flush_total_times,
long long *errs)
{
- int ret;
- size_t i;
- bool found = false;
- virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
- NULL);
- virJSONValuePtr reply = NULL;
- virJSONValuePtr devices;
+ struct qemuBlockStats stats;
+ int nstats = 1;
+ int ret = -1;
*rd_req = *rd_bytes = -1;
*wr_req = *wr_bytes = *errs = -1;
@@ -1732,9 +1728,45 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
if (flush_total_times)
*flush_total_times = -1;
+ if (qemuMonitorJSONGetAllBlockStatsInfo(mon, dev_name, &stats, nstats) !=
nstats)
+ goto cleanup;
+
+ *rd_req = stats.rd_req;
+ *rd_bytes = stats.rd_bytes;
+ *rd_total_times = stats.rd_total_times;
+ *wr_req = stats.wr_req;
+ *wr_bytes = stats.wr_bytes;
+ *wr_total_times = stats.wr_total_times;
+ *flush_req = stats.flush_req;
+ *flush_total_times = stats.flush_total_times;
+ *errs = stats.errs;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+
+int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
+ const char *dev_name,
+ struct qemuBlockStats *blockstats,
+ int nstats)
+{
+ int ret;
+ size_t i;
+ bool found = false;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
+ NULL);
+ virJSONValuePtr reply = NULL;
+ virJSONValuePtr devices;
+
if (!cmd)
return -1;
+ if (!blockstats || nstats <= 0)
+ return -1;
+
ret = qemuMonitorJSONCommand(mon, cmd, &reply);
if (ret == 0)
@@ -1750,33 +1782,41 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
goto cleanup;
}
+ ret = 0;
for (i = 0; i < virJSONValueArraySize(devices); i++) {
virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
virJSONValuePtr stats;
- const char *thisdev;
if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("blockstats device entry was not in expected
format"));
goto cleanup;
}
- if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("blockstats device entry was not in expected
format"));
- goto cleanup;
+ if (ret > nstats) {
+ break;
}
- /* New QEMU has separate names for host & guest side of the disk
- * and libvirt gives the host side a 'drive-' prefix. The passed
- * in dev_name is the guest side though
- */
- if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
- thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
+ if (dev_name != NULL) {
+ const char *thisdev;
+ if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL)
{
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats device entry was not in expected
format"));
+ goto cleanup;
+ }
- if (STRNEQ(thisdev, dev_name))
- continue;
+ /* New QEMU has separate names for host & guest side of the disk
+ * and libvirt gives the host side a 'drive-' prefix. The passed
+ * in dev_name is the guest side though
+ */
+ if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
+ thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+ if (STRNEQ(thisdev, dev_name))
+ continue;
+
+ found = true;
+ }
- found = true;
if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
stats->type != VIR_JSON_TYPE_OBJECT) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1784,74 +1824,74 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
goto cleanup;
}
- if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", rd_bytes) <
0) {
+ if (virJSONValueObjectGetNumberLong(stats, "rd_bytes",
&blockstats->rd_bytes) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"rd_bytes");
goto cleanup;
}
- if (virJSONValueObjectGetNumberLong(stats, "rd_operations", rd_req)
< 0) {
+ if (virJSONValueObjectGetNumberLong(stats, "rd_operations",
&blockstats->rd_req) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"rd_operations");
goto cleanup;
}
- if (rd_total_times &&
- virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
+ if (virJSONValueObjectHasKey(stats, "rd_total_time_ns") &&
(virJSONValueObjectGetNumberLong(stats, "rd_total_time_ns",
- rd_total_times) < 0)) {
+ &blockstats->rd_total_times) < 0))
{
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"rd_total_time_ns");
goto cleanup;
}
- if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", wr_bytes) <
0) {
+ if (virJSONValueObjectGetNumberLong(stats, "wr_bytes",
&blockstats->wr_bytes) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"wr_bytes");
goto cleanup;
}
- if (virJSONValueObjectGetNumberLong(stats, "wr_operations", wr_req)
< 0) {
+ if (virJSONValueObjectGetNumberLong(stats, "wr_operations",
&blockstats->wr_req) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"wr_operations");
goto cleanup;
}
- if (wr_total_times &&
- virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
+ if (virJSONValueObjectHasKey(stats, "wr_total_time_ns") &&
(virJSONValueObjectGetNumberLong(stats, "wr_total_time_ns",
- wr_total_times) < 0)) {
+ &blockstats->wr_total_times) < 0))
{
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"wr_total_time_ns");
goto cleanup;
}
- if (flush_req &&
- virJSONValueObjectHasKey(stats, "flush_operations") &&
+ if (virJSONValueObjectHasKey(stats, "flush_operations") &&
(virJSONValueObjectGetNumberLong(stats, "flush_operations",
- flush_req) < 0)) {
+ &blockstats->flush_req) < 0)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"flush_operations");
goto cleanup;
}
- if (flush_total_times &&
- virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
+ if (virJSONValueObjectHasKey(stats, "flush_total_time_ns") &&
(virJSONValueObjectGetNumberLong(stats, "flush_total_time_ns",
- flush_total_times) < 0)) {
+ &blockstats->flush_total_times) <
0)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot read %s statistic"),
"flush_total_time_ns");
goto cleanup;
}
+ blockstats->errs = -1; /* meaningless for QEMU */
+
+ ret++;
+ blockstats++;
}
- if (!found) {
+ if (dev_name != NULL && !found) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find statistics for device '%s'"),
dev_name);
+ ret = 0;
goto cleanup;
}
- ret = 0;
cleanup:
virJSONValueFree(cmd);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index d8c9308..79058c1 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -79,6 +79,10 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
long long *flush_req,
long long *flush_total_times,
long long *errs);
+int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
+ const char *dev_name,
+ struct qemuBlockStats *stats,
+ int nstats);
int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
int *nparams);
int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
--
1.9.3