---
src/qemu/qemu_driver.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 187 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 03fadae..2c2bf56 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6842,6 +6842,192 @@ cleanup:
return ret;
}
+static int
+qemudDomainBlockStatsFlags (virDomainPtr dom,
+ const char *path,
+ virDomainBlockStatsFlagsPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ int i, tmp, ret = -1;
+ virDomainObjPtr vm;
+ virDomainDiskDefPtr disk = NULL;
+ qemuDomainObjPrivatePtr priv;
+ long long rd_req, rd_bytes, wr_req, wr_bytes, rd_total_times;
+ long long wr_total_times, flush_req, flush_total_times, errs;
+
+ virCheckFlags(0, -1);
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (*nparams != 0) {
+ for (i = 0 ; i < vm->def->ndisks ; i++) {
+ if (STREQ(path, vm->def->disks[i]->dst)) {
+ disk = vm->def->disks[i];
+ break;
+ }
+ }
+
+ if (!disk) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path: %s"), path);
+ goto cleanup;
+ }
+
+ if (!disk->info.alias) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("missing disk device alias name for %s"),
disk->dst);
+ goto cleanup;
+ }
+ }
+
+ priv = vm->privateData;
+ VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+ goto cleanup;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ tmp = *nparams;
+ ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);
+
+ if (tmp == 0) {
+ qemuDomainObjExitMonitor(driver, vm);
+ goto endjob;
+ }
+
+ ret = qemuMonitorGetBlockStatsInfo(priv->mon,
+ disk->info.alias,
+ &rd_req,
+ &rd_bytes,
+ &rd_total_times,
+ &wr_req,
+ &wr_bytes,
+ &wr_total_times,
+ &flush_req,
+ &flush_total_times,
+ &errs);
+
+ qemuDomainObjExitMonitor(driver, vm);
+
+ if (ret < 0)
+ goto endjob;
+
+ /* Field 'errs' is meaningless for QEMU, won't set it. */
+ for (i = 0; i < *nparams; i++) {
+ virDomainBlockStatsFlagsPtr param = ¶ms[i];
+
+ switch (i) {
+ case 0: /* fill write_bytes here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES) ==
NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field write bytes too long for
destination"));
+ goto cleanup;
+ }
+ param->value = wr_bytes;
+ break;
+
+ case 1: /* fill wr_operations here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ) ==
NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field write requests too long for
destination"));
+ goto cleanup;
+ }
+ param->value = wr_req;
+ break;
+
+ case 2: /* fill read_bytes here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_READ_BYTES) ==
NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field read bytes too long for
destination"));
+ goto cleanup;
+ }
+ param->value = rd_bytes;
+ break;
+
+ case 3: /* fill rd_operations here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_READ_REQ) ==
NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field read requests too long for
destination"));
+ goto cleanup;
+ }
+ param->value = rd_req;
+ break;
+
+ case 4: /* fill flush_operations here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ) ==
NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field flush requests too long for
destination"));
+ goto cleanup;
+ }
+ param->value = flush_req;
+ break;
+
+ case 5: /* fill wr_total_times_ns here */
+ if (virStrcpyStatic(param->field,
VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field write total times too long
for destination"));
+ goto cleanup;
+ }
+ param->value = wr_total_times;
+ break;
+
+ case 6: /* fill rd_total_times_ns here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES)
== NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field read total times too long
for destination"));
+ goto cleanup;
+ }
+ param->value = rd_total_times;
+ break;
+
+ case 7: /* fill flush_total_times_ns here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES)
== NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field flush total times too long
for destination"));
+ goto cleanup;
+ }
+ param->value = flush_total_times;
+ break;
+
+ default:
+ break;
+ /* should not hit here */
+ }
+ }
+
+endjob:
+ if (qemuDomainObjEndJob(driver, vm) == 0)
+ vm = NULL;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
#ifdef __linux__
static int
qemudDomainInterfaceStats (virDomainPtr dom,
@@ -9489,6 +9675,7 @@ static virDriver qemuDriver = {
.domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
.domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
.domainBlockStats = qemudDomainBlockStats, /* 0.4.1 */
+ .domainBlockStatsFlags = qemudDomainBlockStatsFlags, /* 0.9.5 */
.domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */
.domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */
.domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
--
1.7.6