[libvirt] [PATCH 3/5] qemu: Implement individual vcpu hotplug API

Peter Krempa pkrempa at redhat.com
Fri Feb 10 17:10:20 UTC 2017


Add code that validates user's selection of cores and then uses the
existing code to plug in the vCPU.
---
 src/qemu/qemu_driver.c  |  74 +++++++++++++++++++++++
 src/qemu/qemu_hotplug.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_hotplug.h |   7 +++
 3 files changed, 234 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 89bc833de..2b875b3e9 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20190,6 +20190,79 @@ qemuDomainSetGuestVcpus(virDomainPtr dom,
 }


+static int
+qemuDomainSetVcpu(virDomainPtr dom,
+                  const char *cpumap,
+                  int state,
+                  unsigned int flags)
+{
+    virQEMUDriverPtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr def = NULL;
+    virDomainDefPtr persistentDef = NULL;
+    virBitmapPtr map = NULL;
+    ssize_t lastvcpu;
+    int ret = -1;
+
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+    if (state != 0 && state != 1) {
+        virReportInvalidArg(state, "%s", _("unsupported state value"));
+        return -1;
+    }
+
+    if (virBitmapParse(cpumap, &map, QEMU_GUEST_VCPU_MAX_ID) < 0)
+        goto cleanup;
+
+    if ((lastvcpu = virBitmapLastSetBit(map)) < 0) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("no vcpus selected for modification"));
+        goto cleanup;
+    }
+
+    if (!(vm = qemuDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainSetVcpuEnsureACL(dom->conn, vm->def, flags) < 0)
+        goto cleanup;
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
+        goto endjob;
+
+    if (persistentDef) {
+        if (lastvcpu >= virDomainDefGetVcpusMax(persistentDef)) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("vcpu %zd is not present in persistent config"),
+                           lastvcpu);
+            goto endjob;
+        }
+    }
+
+    if (def) {
+        if (lastvcpu >= virDomainDefGetVcpusMax(def)) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("vcpu %zd is not present in live config"),
+                           lastvcpu);
+            goto endjob;
+        }
+    }
+
+    ret = qemuDomainSetVcpuInternal(driver, vm, def, persistentDef, map, !!state);
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+    virBitmapFree(map);
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
     .name = QEMU_DRIVER_NAME,
     .connectOpen = qemuConnectOpen, /* 0.2.0 */
@@ -20403,6 +20476,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainMigrateStartPostCopy = qemuDomainMigrateStartPostCopy, /* 1.3.3 */
     .domainGetGuestVcpus = qemuDomainGetGuestVcpus, /* 2.0.0 */
     .domainSetGuestVcpus = qemuDomainSetGuestVcpus, /* 2.0.0 */
+    .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */
 };


diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 2f209f12b..363d1070b 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -5700,3 +5700,156 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
     virObjectUnref(cfg);
     return ret;
 }
+
+
+static void
+qemuDomainSetVcpuInactive(virDomainDefPtr def,
+                          virBitmapPtr map,
+                          bool state)
+{
+    virDomainVcpuDefPtr vcpu;
+    ssize_t next = -1;
+
+    def->individualvcpus = true;
+
+    while ((next = virBitmapNextSetBit(map, next)) > 0) {
+        if (!(vcpu = virDomainDefGetVcpu(def, next)))
+            continue;
+
+        vcpu->online = state;
+        vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
+        vcpu->order = 0;
+    }
+}
+
+
+/**
+ * qemuDomainFilterHotplugVcpuEntities:
+ *
+ * Returns a bitmap of hotpluggable vcpu entities that correspond to the logical
+ * vcpus requested in @vcpus.
+ */
+static virBitmapPtr
+qemuDomainFilterHotplugVcpuEntities(virDomainDefPtr def,
+                                    virBitmapPtr vcpus,
+                                    bool state)
+{
+    qemuDomainVcpuPrivatePtr vcpupriv;
+    virDomainVcpuDefPtr vcpu;
+    virBitmapPtr map = NULL;
+    virBitmapPtr ret = NULL;
+    ssize_t next = -1;
+    size_t i;
+
+    if (!(map = virBitmapNewCopy(vcpus)))
+        return NULL;
+
+    /* make sure that all selected vcpus are in the correct state */
+    while ((next = virBitmapNextSetBit(map, next)) > 0) {
+        if (!(vcpu = virDomainDefGetVcpu(def, next)))
+            continue;
+
+        if (vcpu->online == state) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("vcpu '%zu' is already in requested state"), next);
+            goto cleanup;
+        }
+
+        if (vcpu->online && !vcpu->hotpluggable) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("vcpu '%zu' can't be hotunplugged"), next);
+            goto cleanup;
+        }
+    }
+
+    /* Make sure that all vCPUs belonging to a single hotpluggable entity were
+     * selected and then de-select any sub-threads of it. */
+    next = -1;
+    while ((next = virBitmapNextSetBit(map, next)) > 0) {
+        if (!(vcpu = virDomainDefGetVcpu(def, next)))
+            continue;
+
+        vcpupriv =  QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
+
+        if (vcpupriv->vcpus == 0) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("vcpu '%zu' belongs to a larger hotpluggable entity, "
+                             "but siblings were not selected"), next);
+            goto cleanup;
+        }
+
+        for (i = next + 1; i < next + vcpupriv->vcpus; i++) {
+            if (!virBitmapIsBitSet(map, i)) {
+                virReportError(VIR_ERR_INVALID_ARG,
+                               _("vcpu '%zu' was not selected but it belongs to "
+                                 "hotpluggable entity '%zu-%zu' which was "
+                                 "partially selected"),
+                               i, next, next + vcpupriv->vcpus - 1);
+                goto cleanup;
+            }
+
+            /* clear the subthreads */
+            ignore_value(virBitmapClearBit(map, i));
+        }
+    }
+
+    VIR_STEAL_PTR(ret, map);
+
+ cleanup:
+    virBitmapFree(map);
+    return ret;
+}
+
+
+int
+qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          virDomainDefPtr def,
+                          virDomainDefPtr persistentDef,
+                          virBitmapPtr map,
+                          bool state)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virBitmapPtr livevcpus = NULL;
+    int ret = -1;
+
+    if (def) {
+        if (!qemuDomainSupportsNewVcpuHotplug(vm)) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("this qemu version does not support specific "
+                             "vCPU hotplug"));
+            goto cleanup;
+        }
+
+        if (!(livevcpus = qemuDomainFilterHotplugVcpuEntities(def, map, state)))
+            goto cleanup;
+
+        /* Make sure that only one hotpluggable entity is selected.
+         * qemuDomainSetVcpusLive allows setting more at once but error
+         * resolution in case of a partial failure is hard, so don't let users
+         * do so */
+        if (virBitmapCountBits(livevcpus) != 1) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("only one hotpluggable entity can be selected"));
+            goto cleanup;
+        }
+    }
+
+    if (livevcpus &&
+        qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0)
+        goto cleanup;
+
+    if (persistentDef) {
+        qemuDomainSetVcpuInactive(persistentDef, map, state);
+
+        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virBitmapFree(livevcpus);
+    virObjectUnref(cfg);
+    return ret;
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 13242eec9..0b11c1ed9 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -143,4 +143,11 @@ int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
                                unsigned int nvcpus,
                                bool hotpluggable);

+int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              virDomainDefPtr def,
+                              virDomainDefPtr persistentDef,
+                              virBitmapPtr vcpus,
+                              bool state);
+
 #endif /* __QEMU_HOTPLUG_H__ */
-- 
2.11.0




More information about the libvir-list mailing list