--- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list