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)
+ 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,
+ 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 8c84cdb..2d1afc4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -410,6 +410,11 @@ int qemuMonitorBlockStatsUpdateThreshold(qemuMonitorPtr mon,
virHashTablePtr stats)
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 46383d7..6cfba99 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2048,6 +2048,36 @@ qemuMonitorJSONBlockStatsUpdateThreshold(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 2f90b5c..fe00f20 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -79,6 +79,9 @@ int qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
bool backingChain);
int qemuMonitorJSONBlockStatsUpdateThreshold(qemuMonitorPtr mon,
virHashTablePtr stats);
+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.3