Implement the support of get block io throttle for qemu driver. Signed-off-by: Zhi Yong Wu <wuzhy@xxxxxxxxxxxxxxxxxx> Signed-off-by: Lei Li <lilei@xxxxxxxxxxxxxxxxxx> --- src/qemu/qemu_driver.c | 55 ++++++++++++++++ src/qemu/qemu_monitor.c | 18 +++++ src/qemu/qemu_monitor.h | 5 ++ src/qemu/qemu_monitor_json.c | 145 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 ++ src/qemu/qemu_monitor_text.c | 117 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 ++ 7 files changed, 350 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b41a7d3..6be6301 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10712,6 +10712,60 @@ cleanup: return ret; } +static int +qemuDomainGetBlockIoThrottle(virDomainPtr dom, + const char *disk, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + qemuDomainObjPrivatePtr priv; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + const char *device = NULL; + int ret = -1; + + qemuDriverLock(driver); + virUUIDFormat(dom->uuid, uuidstr); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + 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; + } + device = qemuDiskPathToAlias(vm, disk); + + if (!device) { + goto cleanup; + } + + if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + qemuDomainObjEnterMonitorWithDriver(driver, vm); + priv = vm->privateData; + ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, reply, flags); + qemuDomainObjExitMonitorWithDriver(driver, vm); + + if (qemuDomainObjEndJob(driver, vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + VIR_FREE(device); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, .name = "QEMU", @@ -10855,6 +10909,7 @@ static virDriver qemuDriver = { .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */ .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */ .domainSetBlockIoThrottle = qemuDomainSetBlockIoThrottle, /* 0.9.8 */ + .domainGetBlockIoThrottle = qemuDomainGetBlockIoThrottle, /* 0.9.8 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index b061631..7a23fd8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2560,6 +2560,24 @@ int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon, return ret; } +int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags) +{ + int ret; + + VIR_DEBUG("mon=%p, device=%p, reply=%p, flags=%x", + mon, device, reply, flags); + + if (mon->json) { + ret = qemuMonitorJSONGetBlockIoThrottle(mon, device, reply, flags); + } else { + ret = qemuMonitorTextGetBlockIoThrottle(mon, device, reply, flags); + } + return ret; +} + int qemuMonitorVMStatusToPausedReason(const char *status) { int st; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 1269430..c172b2b 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -520,6 +520,11 @@ int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon, virDomainBlockIoThrottleInfoPtr info, unsigned int flags); +int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2f93830..32410e3 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3290,3 +3290,148 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon, return ret; } +static int +qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result, + const char *device, + virDomainBlockIoThrottleInfoPtr reply) +{ + virJSONValuePtr io_throttle; + int ret = -1; + int i; + int found = 0; + + io_throttle = virJSONValueObjectGet(result, "return"); + + if (!io_throttle ||io_throttle->type != VIR_JSON_TYPE_ARRAY) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _(" block_io_throttle reply was missing device list ")); + goto cleanup; + } + + for (i = 0; i < virJSONValueArraySize(io_throttle); i++) { + virJSONValuePtr temp_dev = virJSONValueArrayGet(io_throttle, i); + virJSONValuePtr inserted; + const char *current_dev; + + if (!temp_dev || temp_dev->type !=VIR_JSON_TYPE_OBJECT) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block io throttle device entry was not in expected format")); + goto cleanup; + } + + if ((current_dev = virJSONValueObjectGetString(temp_dev, "device")) == NULL) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block io throttle device entry was not in expected format")); + goto cleanup; + } + + if(STRPREFIX(current_dev, QEMU_DRIVE_HOST_PREFIX)) + current_dev += strlen(QEMU_DRIVE_HOST_PREFIX); + + if (STREQ(current_dev, device)) + continue; + + found = 1; + if ((inserted = virJSONValueObjectGet(temp_dev, "inserted")) == NULL || + inserted->type != VIR_JSON_TYPE_OBJECT) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block io throttle inserted entry was not in expected format")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "bps", &reply->bps) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "bps"); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "bps_rd", &reply->bps_rd) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "bps_rd"); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "bps_wr", &reply->bps_wr) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "bps_wr"); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "iops", &reply->iops) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "iops"); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "iops_rd", &reply->iops_rd) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "iops_rd"); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUlong(inserted, "iops_wr", &reply->iops_wr) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot read %s"), + "iops_wr"); + goto cleanup; + } + break; + } + + if (!found) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot found info for device '%s'"), + device); + goto cleanup; + } + ret = 0; + +cleanup: + return ret; +} + +int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags) +{ + int ret = -1; + virJSONValuePtr cmd = NULL; + virJSONValuePtr result = NULL; + + if (!flags) { + cmd = qemuMonitorJSONMakeCommand("query-block", + NULL); + } + + if (!cmd) { + return -1; + } + + ret = qemuMonitorJSONCommand(mon, cmd, &result); + + if (ret == 0 && virJSONValueObjectHasKey(result, "error")) { + if (qemuMonitorJSONHasError(result, "DeviceNotActive")) + qemuReportError(VIR_ERR_OPERATION_INVALID, + _("No active operation on device: %s"), device); + else if (qemuMonitorJSONHasError(result, "NotSupported")) + qemuReportError(VIR_ERR_OPERATION_INVALID, + _("Operation is not supported for device: %s"), device); + else + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unexpected error")); + ret = -1; + } + + if (ret == 0 && !flags) + ret = qemuMonitorJSONBlockIoThrottleInfo(result, device, reply); + + virJSONValueFree(cmd); + virJSONValueFree(result); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 36cae79..9562908 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -255,4 +255,9 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon, virDomainBlockIoThrottleInfoPtr info, unsigned int flags); +int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags); + #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 13fdf55..496e926 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -3433,3 +3433,120 @@ cleanup: return ret; } +static int qemuMonitorTextParseBlockIoThrottle(const char *result, + const char *device, + virDomainBlockIoThrottleInfoPtr reply) +{ + char *dummy = NULL; + int ret = -1; + const char *p, *eol; + int devnamelen = strlen(device); + int tmp; + + p = result; + + while (*p) { + if (STRPREFIX(p, QEMU_DRIVE_HOST_PREFIX)) + p += strlen(QEMU_DRIVE_HOST_PREFIX); + + if (STREQLEN(p, device, devnamelen) && + p[devnamelen] == ':' && p[devnamelen+1] == ' ') { + + eol = strchr(p, '\n'); + if (!eol) + eol = p + strlen(p); + + p += devnamelen + 2; /*Skip to first label. */ + + while (*p) { + if (STRPREFIX(p, "bps=")) { + p += strlen("bps="); + if (virStrToLong_ull(p, &dummy, 10, &reply->bps) == -1) + VIR_DEBUG("error reading bps: %s", p); + } else if (STRPREFIX(p, "bps_rd=")) { + p += strlen("bps_rd="); + if (virStrToLong_ull(p, &dummy, 10, &reply->bps_rd) == -1) + VIR_DEBUG("error reading bps_rd: %s", p); + } else if (STRPREFIX(p, "bps_wr=")) { + p += strlen("bps_wr="); + if (virStrToLong_ull(p, &dummy, 10, &reply->bps_wr) == -1) + VIR_DEBUG("error reading bps_wr: %s", p); + } else if (STRPREFIX(p, "iops=")) { + p += strlen("iops="); + if (virStrToLong_ull(p, &dummy, 10, &reply->iops) == -1) + VIR_DEBUG("error reading iops: %s", p); + } else if (STRPREFIX(p, "iops_rd=")) { + p += strlen("iops_rd="); + if (virStrToLong_ull(p, &dummy, 10, &reply->iops_rd) == -1) + VIR_DEBUG("error reading iops_rd: %s", p); + } else if (STRPREFIX(p, "iops_wr=")) { + p += strlen("iops_wr="); + if (virStrToLong_ull(p, &dummy, 10, &reply->iops_wr) == -1) + VIR_DEBUG("error reading iops_wr: %s", p); + } else { + VIR_DEBUG(" unknown block info %s", p); + } + + /* Skip to next label. */ + p = strchr (p, ' '); + if (!p || p >= eol) + break; + p++; + } + ret = 0; + goto cleanup; + } + + /* Skip to next line. */ + p = strchr (p, '\n'); + if (!p) + break; + p++; + } + + qemuReportError(VIR_ERR_INVALID_ARG, + _("no info for device '%s'"), device); + +cleanup: + return ret; +} + +int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags) +{ + char *cmd = NULL; + char *result = NULL; + int ret = 0; + + if (!flags) { + ret = virAsprintf(&cmd, "info block"); + } + + if (ret < 0) { + virReportOOMError(); + return -1; + } + + if (qemuMonitorHMPCommand(mon, cmd, &result) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot run monitor command")); + ret = -1; + goto cleanup; + } + + if (strstr(result, "\ninfo ")) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", + _("info block not supported by this qemu")); + ret = -1; + goto cleanup; + } + ret = qemuMonitorTextParseBlockIoThrottle(result, device, reply); + +cleanup: + VIR_FREE(cmd); + VIR_FREE(result); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index d64fc55..ded5807 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -248,4 +248,9 @@ int qemuMonitorTextSetBlockIoThrottle(qemuMonitorPtr mon, virDomainBlockIoThrottleInfoPtr info, unsigned int flags); +int qemuMonitorTextGetBlockIoThrottle(qemuMonitorPtr mon, + const char *device, + virDomainBlockIoThrottleInfoPtr reply, + unsigned int flags); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list