[libvirt] [RFC PATCHv2 8/8] threshold: add write threshold setting in qemu

Eric Blake eblake at redhat.com
Fri Jun 12 19:29:32 UTC 2015


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 at 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




More information about the libvir-list mailing list