https://bugzilla.redhat.com/show_bug.cgi?id=1545732
Implement the QEMU driver mechanism in order to set the polling
parameters for an IOThread within the bounds specified by the
QEMU qapi parameter passing.
Based heavily on patches originally posted by Pavel Hrdina
<phrdina(a)redhat.com>, but modified to only handle alterations
for a running guest. For the most part the API names changed,
the typed parameters removed the poll enabled value, and the
capabilities check was moved to just before the live attempt
to set. Since changes are only supported for a running guest,
no guest XML alterations were kept.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/qemu/qemu_driver.c | 202 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 202 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c87a0db86d..be668b3217 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5899,6 +5899,35 @@ qemuDomainHotplugAddIOThread(virQEMUDriverPtr driver,
goto cleanup;
}
+
+static int
+qemuDomainHotplugModIOThread(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuMonitorIOThreadInfo iothread)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int rc;
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_IOTHREAD_POLLING)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("IOThreads polling is not supported for this QEMU"));
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ rc = qemuMonitorSetIOThread(priv->mon, &iothread);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+
static int
qemuDomainHotplugDelIOThread(virQEMUDriverPtr driver,
virDomainObjPtr vm,
@@ -6015,9 +6044,107 @@ qemuDomainDelIOThreadCheck(virDomainDefPtr def,
return 0;
}
+
+/**
+ * @params: Pointer to params list
+ * @nparams: Number of params to be parsed
+ * @iothread: Buffer to store the values
+ *
+ * The following is a description of each value parsed:
+ *
+ * - "poll-max-ns" for each IOThread is the maximum time in nanoseconds
+ * to allow each polling interval to occur. A polling interval is a
+ * period of time allowed for a thread to process data before it returns
+ * the CPU quantum back to the host. A value set too small will not allow
+ * the IOThread to run long enough on a CPU to process data. A value set
+ * too high will consume too much CPU time per IOThread failing to allow
+ * other threads running on the CPU to get time. A value of 0 (zero) will
+ * disable the polling.
+ *
+ * - "poll-grow" - factor to grow the current polling time when deemed
+ * necessary. If a 0 (zero) value is provided, QEMU currently doubles
+ * its polling interval unless the current value is greater than the
+ * poll-max-ns.
+ *
+ * - "poll-shrink" - divisor to reduced the current polling time when deemed
+ * necessary. If a 0 (zero) value is provided, QEMU resets the polling
+ * interval to 0 (zero) allowing the poll-grow to manipulate the time.
+ *
+ * QEMU keeps track of the polling time elapsed and may grow or shrink the
+ * its polling interval based upon its heuristic algorithm. It is possible
+ * that calculations determine that it has found a "sweet spot" and no
+ * ajustments are made. The polling time value is not available.
+ *
+ * Returns 0 on success, -1 on failure with error set.
+ */
+static int
+qemuDomainIOThreadParseParams(virTypedParameterPtr params,
+ int nparams,
+ qemuMonitorIOThreadInfoPtr iothread)
+{
+ if (virTypedParamsValidate(params, nparams,
+ VIR_DOMAIN_IOTHREAD_POLL_MAX_NS,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_IOTHREAD_POLL_GROW,
+ VIR_TYPED_PARAM_UINT,
+ VIR_DOMAIN_IOTHREAD_POLL_SHRINK,
+ VIR_TYPED_PARAM_UINT,
+ NULL) < 0)
+ return -1;
+
+ if (virTypedParamsGetULLong(params, nparams,
+ VIR_DOMAIN_IOTHREAD_POLL_MAX_NS,
+ &iothread->poll_max_ns) < 0)
+ return -1;
+
+ if (virTypedParamsGetUInt(params, nparams,
+ VIR_DOMAIN_IOTHREAD_POLL_GROW,
+ &iothread->poll_grow) < 0)
+ return -1;
+
+ if (virTypedParamsGetUInt(params, nparams,
+ VIR_DOMAIN_IOTHREAD_POLL_SHRINK,
+ &iothread->poll_shrink) < 0)
+ return -1;
+
+ if (iothread->poll_max_ns > INT_MAX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("poll-max-ns (%llu) must be less than or equal to
%d"),
+ iothread->poll_max_ns, INT_MAX);
+ return -1;
+ }
+
+ if (iothread->poll_grow > INT_MAX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("poll-grow (%u) must be less than or equal to %d"),
+ iothread->poll_grow, INT_MAX);
+ return -1;
+ }
+
+ if (iothread->poll_shrink > INT_MAX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("poll-shrink (%u) must be less than or equal to %d"),
+ iothread->poll_shrink, INT_MAX);
+ return -1;
+ }
+
+ if ((iothread->poll_grow > 0 || iothread->poll_shrink > 0) &&
+ iothread->poll_max_ns == 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("poll-grow or poll-shrink is set for iothread id "
+ "'%u' but poll-max-ns is not set"),
+ iothread->iothread_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+
typedef enum {
VIR_DOMAIN_IOTHREAD_ACTION_ADD,
VIR_DOMAIN_IOTHREAD_ACTION_DEL,
+ VIR_DOMAIN_IOTHREAD_ACTION_MOD,
} virDomainIOThreadAction;
static int
@@ -6068,6 +6195,20 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver,
goto endjob;
break;
+
+ case VIR_DOMAIN_IOTHREAD_ACTION_MOD:
+ if (!(virDomainIOThreadIDFind(def, iothread.iothread_id))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("cannot find IOThread '%u' in
iothreadids"),
+ iothread.iothread_id);
+ goto endjob;
+ }
+
+ if (qemuDomainHotplugModIOThread(driver, vm, iothread) < 0)
+ goto endjob;
+
+ break;
+
}
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps)
< 0)
@@ -6091,6 +6232,14 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver,
virDomainIOThreadIDDel(persistentDef, iothread.iothread_id);
+ break;
+
+ case VIR_DOMAIN_IOTHREAD_ACTION_MOD:
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("configuring persistent polling values is "
+ "not supported"));
+ goto endjob;
+
break;
}
@@ -6178,6 +6327,58 @@ qemuDomainDelIOThread(virDomainPtr dom,
return ret;
}
+
+/**
+ * @dom: Domain to set IOThread params
+ * @iothread_id: IOThread 'id' that will be modified
+ * @params: List of parameters to change
+ * @nparams: Number of parameters in the list
+ * @flags: Flags for the set (only supports live alteration)
+ *
+ * Alter the specified @iothread_id with the values provided.
+ *
+ * Returs 0 on success, -1 on failure
+ */
+static int
+qemuDomainSetIOThreadParams(virDomainPtr dom,
+ unsigned int iothread_id,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virQEMUDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ qemuMonitorIOThreadInfo iothread = {0};
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE, -1);
+
+ if (iothread_id == 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid value of 0 for iothread_id"));
+ goto cleanup;
+ }
+
+ iothread.iothread_id = iothread_id;
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+ goto cleanup;
+
+ if (virDomainSetIOThreadParamsEnsureACL(dom->conn, vm->def, flags) < 0)
+ goto cleanup;
+
+ if (qemuDomainIOThreadParseParams(params, nparams, &iothread) < 0)
+ goto cleanup;
+
+ ret = qemuDomainChgIOThread(driver, vm, iothread,
+ VIR_DOMAIN_IOTHREAD_ACTION_MOD, flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
virQEMUDriverPtr driver = dom->conn->privateData;
@@ -21955,6 +22156,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
.domainPinIOThread = qemuDomainPinIOThread, /* 1.2.14 */
.domainAddIOThread = qemuDomainAddIOThread, /* 1.2.15 */
.domainDelIOThread = qemuDomainDelIOThread, /* 1.2.15 */
+ .domainSetIOThreadParams = qemuDomainSetIOThreadParams, /* 4.9.0 */
.domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */
.domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
.nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
--
2.17.1