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(a)redhat.com>
---
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