|
|
6ae9ed |
From f44af1507adb8d05bd5e2992734d7f275c34fc6a Mon Sep 17 00:00:00 2001
|
|
|
6ae9ed |
Message-Id: <f44af1507adb8d05bd5e2992734d7f275c34fc6a@dist-git>
|
|
|
6ae9ed |
From: Peter Krempa <pkrempa@redhat.com>
|
|
|
6ae9ed |
Date: Wed, 24 Aug 2016 16:11:38 -0400
|
|
|
6ae9ed |
Subject: [PATCH] qemu: Use modern vcpu hotplug approach if possible
|
|
|
6ae9ed |
|
|
|
6ae9ed |
https://bugzilla.redhat.com/show_bug.cgi?id=1097930
|
|
|
6ae9ed |
https://bugzilla.redhat.com/show_bug.cgi?id=1224341
|
|
|
6ae9ed |
|
|
|
6ae9ed |
To allow unplugging the vcpus, hotplugging of vcpus on platforms which
|
|
|
6ae9ed |
require to plug multiple logical vcpus at once or plugging them in an
|
|
|
6ae9ed |
arbitrary order it's necessary to use the new device_add interface for
|
|
|
6ae9ed |
vcpu hotplug.
|
|
|
6ae9ed |
|
|
|
6ae9ed |
This patch adds support for the device_add interface using the old
|
|
|
6ae9ed |
setvcpus API by implementing an algorithm to select the appropriate
|
|
|
6ae9ed |
entities to plug in.
|
|
|
6ae9ed |
|
|
|
6ae9ed |
(cherry picked from commit 6d4ee77d754df83a0d006c8b503042b437c14df8)
|
|
|
6ae9ed |
---
|
|
|
6ae9ed |
src/qemu/qemu_driver.c | 157 +++++++++++++++++++++++++++++++++++++++++++------
|
|
|
6ae9ed |
1 file changed, 140 insertions(+), 17 deletions(-)
|
|
|
6ae9ed |
|
|
|
6ae9ed |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
6ae9ed |
index 43e00ff..900aacd 100644
|
|
|
6ae9ed |
--- a/src/qemu/qemu_driver.c
|
|
|
6ae9ed |
+++ b/src/qemu/qemu_driver.c
|
|
|
6ae9ed |
@@ -4600,46 +4600,67 @@ qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
virDomainObjPtr vm,
|
|
|
6ae9ed |
unsigned int vcpu)
|
|
|
6ae9ed |
{
|
|
|
6ae9ed |
- qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
6ae9ed |
+ virJSONValuePtr vcpuprops = NULL;
|
|
|
6ae9ed |
virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
|
|
|
6ae9ed |
qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
|
|
6ae9ed |
+ unsigned int nvcpus = vcpupriv->vcpus;
|
|
|
6ae9ed |
+ bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm);
|
|
|
6ae9ed |
int ret = -1;
|
|
|
6ae9ed |
int rc;
|
|
|
6ae9ed |
int oldvcpus = virDomainDefGetVcpus(vm->def);
|
|
|
6ae9ed |
+ size_t i;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- if (vcpuinfo->online) {
|
|
|
6ae9ed |
- virReportError(VIR_ERR_INVALID_ARG,
|
|
|
6ae9ed |
- _("vCPU '%u' is already online"), vcpu);
|
|
|
6ae9ed |
- return -1;
|
|
|
6ae9ed |
+ if (newhotplug) {
|
|
|
6ae9ed |
+ if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
|
|
|
6ae9ed |
+ goto cleanup;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
|
|
|
6ae9ed |
+ goto cleanup;
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
|
|
|
6ae9ed |
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- rc = qemuMonitorSetCPU(priv->mon, vcpu, true);
|
|
|
6ae9ed |
+ if (newhotplug) {
|
|
|
6ae9ed |
+ rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops);
|
|
|
6ae9ed |
+ vcpuprops = NULL;
|
|
|
6ae9ed |
+ } else {
|
|
|
6ae9ed |
+ rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true);
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
|
|
|
6ae9ed |
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
|
|
6ae9ed |
goto cleanup;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- virDomainAuditVcpu(vm, oldvcpus, oldvcpus + 1, "update", rc == 0);
|
|
|
6ae9ed |
+ virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);
|
|
|
6ae9ed |
|
|
|
6ae9ed |
if (rc < 0)
|
|
|
6ae9ed |
goto cleanup;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- vcpuinfo->online = true;
|
|
|
6ae9ed |
+ /* start outputting of the new XML element to allow keeping unpluggability */
|
|
|
6ae9ed |
+ if (newhotplug)
|
|
|
6ae9ed |
+ vm->def->individualvcpus = true;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
|
|
|
6ae9ed |
goto cleanup;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- if (qemuDomainValidateVcpuInfo(vm) < 0)
|
|
|
6ae9ed |
- goto cleanup;
|
|
|
6ae9ed |
+ /* validation requires us to set the expected state prior to calling it */
|
|
|
6ae9ed |
+ for (i = vcpu; i < vcpu + nvcpus; i++) {
|
|
|
6ae9ed |
+ vcpuinfo = virDomainDefGetVcpu(vm->def, i);
|
|
|
6ae9ed |
+ vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
|
|
6ae9ed |
|
|
|
6ae9ed |
- if (vcpupriv->tid > 0 &&
|
|
|
6ae9ed |
- qemuProcessSetupVcpu(vm, vcpu) < 0)
|
|
|
6ae9ed |
+ vcpuinfo->online = true;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (vcpupriv->tid > 0 &&
|
|
|
6ae9ed |
+ qemuProcessSetupVcpu(vm, i) < 0)
|
|
|
6ae9ed |
+ goto cleanup;
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (qemuDomainValidateVcpuInfo(vm) < 0)
|
|
|
6ae9ed |
goto cleanup;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
ret = 0;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
cleanup:
|
|
|
6ae9ed |
+ virJSONValueFree(vcpuprops);
|
|
|
6ae9ed |
return ret;
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
|
|
|
6ae9ed |
@@ -4777,6 +4798,96 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
|
|
|
6ae9ed |
|
|
|
6ae9ed |
+/**
|
|
|
6ae9ed |
+ * qemuDomainSelectHotplugVcpuEntities:
|
|
|
6ae9ed |
+ *
|
|
|
6ae9ed |
+ * @def: domain definition
|
|
|
6ae9ed |
+ * @nvcpus: target vcpu count
|
|
|
6ae9ed |
+ *
|
|
|
6ae9ed |
+ * Tries to find which vcpu entities need to be enabled or disabled to reach
|
|
|
6ae9ed |
+ * @nvcpus. This function works in order of the legacy hotplug but is able to
|
|
|
6ae9ed |
+ * skip over entries that are added out of order.
|
|
|
6ae9ed |
+ *
|
|
|
6ae9ed |
+ * Returns the bitmap of vcpus to modify on success, NULL on error.
|
|
|
6ae9ed |
+ */
|
|
|
6ae9ed |
+static virBitmapPtr
|
|
|
6ae9ed |
+qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def,
|
|
|
6ae9ed |
+ unsigned int nvcpus)
|
|
|
6ae9ed |
+{
|
|
|
6ae9ed |
+ virBitmapPtr ret = NULL;
|
|
|
6ae9ed |
+ virDomainVcpuDefPtr vcpu;
|
|
|
6ae9ed |
+ qemuDomainVcpuPrivatePtr vcpupriv;
|
|
|
6ae9ed |
+ unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
|
|
|
6ae9ed |
+ unsigned int curvcpus = virDomainDefGetVcpus(def);
|
|
|
6ae9ed |
+ ssize_t i;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (!(ret = virBitmapNew(maxvcpus)))
|
|
|
6ae9ed |
+ return NULL;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (nvcpus > curvcpus) {
|
|
|
6ae9ed |
+ for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) {
|
|
|
6ae9ed |
+ vcpu = virDomainDefGetVcpu(def, i);
|
|
|
6ae9ed |
+ vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (vcpu->online)
|
|
|
6ae9ed |
+ continue;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (vcpupriv->vcpus == 0)
|
|
|
6ae9ed |
+ continue;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ curvcpus += vcpupriv->vcpus;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (curvcpus > nvcpus) {
|
|
|
6ae9ed |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
6ae9ed |
+ _("target vm vcpu granularity does not allow the "
|
|
|
6ae9ed |
+ "desired vcpu count"));
|
|
|
6ae9ed |
+ goto error;
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ ignore_value(virBitmapSetBit(ret, i));
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+ } else {
|
|
|
6ae9ed |
+ for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) {
|
|
|
6ae9ed |
+ vcpu = virDomainDefGetVcpu(def, i);
|
|
|
6ae9ed |
+ vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (!vcpu->online)
|
|
|
6ae9ed |
+ continue;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (vcpupriv->vcpus == 0)
|
|
|
6ae9ed |
+ continue;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (!vcpupriv->alias)
|
|
|
6ae9ed |
+ continue;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ curvcpus -= vcpupriv->vcpus;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (curvcpus < nvcpus) {
|
|
|
6ae9ed |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
6ae9ed |
+ _("target vm vcpu granularity does not allow the "
|
|
|
6ae9ed |
+ "desired vcpu count"));
|
|
|
6ae9ed |
+ goto error;
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ ignore_value(virBitmapSetBit(ret, i));
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ if (curvcpus != nvcpus) {
|
|
|
6ae9ed |
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
6ae9ed |
+ _("failed to find appropriate hotpluggable vcpus to "
|
|
|
6ae9ed |
+ "reach the desired target vcpu count"));
|
|
|
6ae9ed |
+ goto error;
|
|
|
6ae9ed |
+ }
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ return ret;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+ error:
|
|
|
6ae9ed |
+ virBitmapFree(ret);
|
|
|
6ae9ed |
+ return NULL;
|
|
|
6ae9ed |
+}
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
static int
|
|
|
6ae9ed |
qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
virQEMUDriverConfigPtr cfg,
|
|
|
6ae9ed |
@@ -4790,8 +4901,14 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
char *all_nodes_str = NULL;
|
|
|
6ae9ed |
virBitmapPtr all_nodes = NULL;
|
|
|
6ae9ed |
virErrorPtr err = NULL;
|
|
|
6ae9ed |
+ virBitmapPtr vcpumap = NULL;
|
|
|
6ae9ed |
+ ssize_t nextvcpu = -1;
|
|
|
6ae9ed |
+ int rc = 0;
|
|
|
6ae9ed |
int ret = -1;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
+ if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus)))
|
|
|
6ae9ed |
+ goto cleanup;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
if (virNumaIsAvailable() &&
|
|
|
6ae9ed |
virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
|
|
|
6ae9ed |
if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0,
|
|
|
6ae9ed |
@@ -4810,20 +4927,25 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
|
|
|
6ae9ed |
if (nvcpus > virDomainDefGetVcpus(vm->def)) {
|
|
|
6ae9ed |
- for (i = virDomainDefGetVcpus(vm->def); i < nvcpus; i++) {
|
|
|
6ae9ed |
- if (qemuDomainHotplugAddVcpu(driver, vm, i) < 0)
|
|
|
6ae9ed |
- goto cleanup;
|
|
|
6ae9ed |
+ while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
|
|
|
6ae9ed |
+ if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0)
|
|
|
6ae9ed |
+ break;
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
} else {
|
|
|
6ae9ed |
for (i = virDomainDefGetVcpus(vm->def) - 1; i >= nvcpus; i--) {
|
|
|
6ae9ed |
- if (qemuDomainHotplugDelVcpu(driver, vm, i) < 0)
|
|
|
6ae9ed |
- goto cleanup;
|
|
|
6ae9ed |
+ if ((rc = qemuDomainHotplugDelVcpu(driver, vm, i)) < 0)
|
|
|
6ae9ed |
+ break;
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
|
|
|
6ae9ed |
+ qemuDomainVcpuPersistOrder(vm->def);
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
|
|
|
6ae9ed |
goto cleanup;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
+ if (rc < 0)
|
|
|
6ae9ed |
+ goto cleanup;
|
|
|
6ae9ed |
+
|
|
|
6ae9ed |
ret = 0;
|
|
|
6ae9ed |
|
|
|
6ae9ed |
cleanup:
|
|
|
6ae9ed |
@@ -4838,6 +4960,7 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
|
|
6ae9ed |
VIR_FREE(all_nodes_str);
|
|
|
6ae9ed |
virBitmapFree(all_nodes);
|
|
|
6ae9ed |
virCgroupFree(&cgroup_temp);
|
|
|
6ae9ed |
+ virBitmapFree(vcpumap);
|
|
|
6ae9ed |
|
|
|
6ae9ed |
return ret;
|
|
|
6ae9ed |
}
|
|
|
6ae9ed |
--
|
|
|
6ae9ed |
2.10.0
|
|
|
6ae9ed |
|