On Mon, Jun 22, 2015 at 17:06:46 -0600, Eric Blake wrote:
Time to wire up the new API to call into the QMP command for setting
a write threshold.
For now, the API only allows setting the threshold on the active
layer. But I left TODOs in the series for places that need
touching to find and support node names of backing files, so that
we can use "vda[1]" notation to register for a threshold on the
backing image during an active commit operation.
* 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(a)redhat.com>
---
src/qemu/qemu_driver.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
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, 146 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 72e256b..732f102 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17906,6 +17906,100 @@ 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;
+ const char *node = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_BLOCK_SET_WRITE_THRESHOLD_PROPORTION, -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) ||
+ !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_AUTO_NODE_NAMES)) {
+ 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 (!(node = qemuDomainDiskGetAllocationNode(driver, vm, disk))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("cannot track threshold events on disk
'%s'"),
+ path);
+ goto endjob;
+ }
+
+ cfg = virQEMUDriverGetConfig(driver);
+ if (qemuStorageLimitsRefresh(driver, cfg, vm, disk->src) < 0)
This function begins with a rather long comment explaining that it's not
entirely a good idea to use it on online VMs and especially on
write-enabled disk sources. Shouldn't we query the monitor rather than
use that?
+ goto endjob;
+
+ if (flags & VIR_DOMAIN_BLOCK_SET_WRITE_THRESHOLD_PROPORTION) {
+ /* Caller already sanitized max value to 1000000. Use of
+ * floating point intermediary reduces (but does not
+ * eliminate) rounding error, but since we already document a
+ * granularity of parts per million, it shouldn't matter too
+ * much if the answer is a few bytes off. */
+ threshold *= disk->src->physical / 1e6;
+ } else {
+ if (threshold > disk->src->physical) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("threshold %llu exceeds disk size %llu"),
+ 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:
+ virDomainObjEndAPI(&vm);
+ virObjectUnref(caps);
+ virObjectUnref(cfg);
+ return ret;
+}
+
+
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
virDomainDiskErrorPtr errors,
@@ -20037,6 +20131,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
.nodeSuspendForDuration = qemuNodeSuspendForDuration, /* 0.9.8 */
.domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
.domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
+ .domainBlockSetWriteThreshold = qemuDomainBlockSetWriteThreshold, /* 1.3.0 */
.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 c4b6073..2ff34e2 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1866,6 +1866,19 @@ qemuMonitorBlockStatsUpdateThreshold(qemuMonitorPtr mon,
int
+qemuMonitorBlockSetWriteThreshold(qemuMonitorPtr mon,
+ const char *dev_name,
This function needs a node name passed so it should also be called that
way to avoid confusion since the function lacks docs.
+ 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)
Peter