Time to wire up the new API to call into the QMP command for setting a write threshold. FIXME: This patch does not quite do the right thing. At one point, I tried patching qemu to allow thresholds tied to the device, rather than to a node name, since libvirt is not yet setting node names: https://lists.gnu.org/archive/html/qemu-devel/2015-06/msg02023.html But that is the wrong node (remember, each qcow2 resource has two nodes; one for the guest view, which is tied to the device; and another for the host view which is tied to managing the underlying file; we want the allocation of the underlying file based on host offsets, and not the offset seen by the guest). So this patch will need tweaking to coordinate with a version of qemu that auto-assigns node names, to learn the correct node name rather than merely reusing the device name. * src/qemu/qemu_driver.c (qemuDomainBlockSetWriteThreshold): New function. * src/qemu/qemu_monitor.c (qemuMonitorBlockSetWriteThreshold): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorBlockSetWriteThreshold): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONBlockSetWriteThreshold): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockSetWriteThreshold): Likewise. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- src/qemu/qemu_driver.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 13 ++++++ src/qemu/qemu_monitor.h | 5 +++ src/qemu/qemu_monitor_json.c | 30 ++++++++++++++ src/qemu/qemu_monitor_json.h | 3 ++ 5 files changed, 149 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 74a6680..43073d9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -17994,6 +17994,103 @@ qemuDomainGetBlockIoTune(virDomainPtr dom, return ret; } + +static int +qemuDomainBlockSetWriteThreshold(virDomainPtr dom, + const char *path, + unsigned long long threshold, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + qemuDomainObjPrivatePtr priv; + virDomainDiskDefPtr disk = NULL; + virCapsPtr caps = NULL; + virQEMUDriverConfigPtr cfg = NULL; + char *node = NULL; + int ret = -1; + + virCheckFlags(VIR_DOMAIN_BLOCK_SET_WRITE_THRESHOLD_PERCENTAGE, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + return -1; + priv = vm->privateData; + + if (virDomainBlockSetWriteThresholdEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + goto cleanup; + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_WRITE_THRESHOLD)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("block write threshold not supported by this " + "qemu binary")); + goto cleanup; + } + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + if (!(disk = virDomainDiskByName(vm->def, path, false))) { + virReportError(VIR_ERR_INVALID_ARG, + _("invalid path %s not assigned to domain"), path); + goto endjob; + } + + if (virStorageSourceIsEmpty(disk->src)) { + virReportError(VIR_ERR_INVALID_ARG, + _("disk '%s' does not currently have a source assigned"), + path); + goto endjob; + } + if (virAsprintf(&node, "drive-%s", disk->info.alias) < 0) + goto endjob; + + cfg = virQEMUDriverGetConfig(driver); + if (qemuStorageLimitsRefresh(driver, cfg, vm, disk->src) < 0) + goto endjob; + + if (flags & VIR_DOMAIN_BLOCK_SET_WRITE_THRESHOLD_PERCENTAGE) { + /* Caller already sanitized max value to 100000. Use of + * floating point intermediary reduces (but does not + * eliminate) rounding error, but since we already document a + * granularity of a thousandth of a percentage, it shouldn't + * matter too much if the answer is a few bytes off. */ + threshold *= disk->src->physical / 100000.0; + } else { + if (threshold > disk->src->physical) { + virReportError(VIR_ERR_INVALID_ARG, + _("threshold %lld exceeds disk size %lld"), + threshold, disk->src->physical); + goto endjob; + } + } + + qemuDomainObjEnterMonitor(driver, vm); + ret = qemuMonitorBlockSetWriteThreshold(priv->mon, node, threshold); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + ret = -1; + + + endjob: + qemuDomainObjEndJob(driver, vm); + + cleanup: + VIR_FREE(node); + virDomainObjEndAPI(&vm); + virObjectUnref(caps); + virObjectUnref(cfg); + return ret; +} + + static int qemuDomainGetDiskErrors(virDomainPtr dom, virDomainDiskErrorPtr errors, @@ -20121,6 +20218,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .nodeSuspendForDuration = qemuNodeSuspendForDuration, /* 0.9.8 */ .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */ .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */ + .domainBlockSetWriteThreshold = qemuDomainBlockSetWriteThreshold, /* 1.2.17 */ .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */ .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */ .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 27e5a32..8d9ca84 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1824,6 +1824,19 @@ qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon, int +qemuMonitorBlockSetWriteThreshold(qemuMonitorPtr mon, + const char *dev_name, + unsigned long long threshold) +{ + VIR_DEBUG("dev_name=%s, threshold=%llu", dev_name, threshold); + + QEMU_CHECK_MONITOR_JSON(mon); + + return qemuMonitorJSONBlockSetWriteThreshold(mon, dev_name, threshold); +} + + +int qemuMonitorGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 45afba4..e2832e8 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -397,6 +397,11 @@ int qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon, bool backingChain) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuMonitorBlockSetWriteThreshold(qemuMonitorPtr mon, + const char *dev_name, + unsigned long long threshold) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int qemuMonitorGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2cb3c4b..96168d9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1994,6 +1994,36 @@ qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon, } +int +qemuMonitorJSONBlockSetWriteThreshold(qemuMonitorPtr mon, + const char *dev_name, + unsigned long long threshold) +{ + int ret = -1; + int rc; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-set-write-threshold", + "s:node-name", dev_name, + "U:write-threshold", threshold, + NULL))) + return -1; + + if ((rc = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + + static int qemuMonitorJSONReportBlockExtentError(qemuMonitorBlockExtentError error) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index fb77930..8b41536 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -77,6 +77,9 @@ int qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon, int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon, virHashTablePtr stats, bool backingChain); +int qemuMonitorJSONBlockSetWriteThreshold(qemuMonitorPtr mon, + const char *dev_name, + unsigned long long threshold); int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon, const char *dev_name, unsigned long long *extent); -- 2.4.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list