[libvirt] [PATCH 19/34] qemu: Split up vCPU hotplug and hotunplug

Peter Krempa pkrempa at redhat.com
Fri Nov 20 15:22:09 UTC 2015


There's only very little common code among the two operations. Split the
functions so that the internals are easier to understand and refactor
later.
---
 src/qemu/qemu_driver.c | 210 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 136 insertions(+), 74 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 72879cf..a483220 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4710,31 +4710,15 @@ qemuDomainHotplugVcpus(virQEMUDriverPtr driver,

     qemuDomainObjEnterMonitor(driver, vm);

-    /* We need different branches here, because we want to offline
-     * in reverse order to onlining, so any partial fail leaves us in a
-     * reasonably sensible state */
-    if (nvcpus > vcpus) {
-        for (i = vcpus; i < nvcpus; i++) {
-            /* Online new CPU */
-            rc = qemuMonitorSetCPU(priv->mon, i, true);
-            if (rc == 0)
-                goto unsupported;
-            if (rc < 0)
-                goto exit_monitor;
-
-            vcpus++;
-        }
-    } else {
-        for (i = vcpus - 1; i >= nvcpus; i--) {
-            /* Offline old CPU */
-            rc = qemuMonitorSetCPU(priv->mon, i, false);
-            if (rc == 0)
-                goto unsupported;
-            if (rc < 0)
-                goto exit_monitor;
+    for (i = vcpus; i < nvcpus; i++) {
+        /* Online new CPU */
+        rc = qemuMonitorSetCPU(priv->mon, i, true);
+        if (rc == 0)
+            goto unsupported;
+        if (rc < 0)
+            goto exit_monitor;

-            vcpus--;
-        }
+        vcpus++;
     }

     /* hotplug succeeded */
@@ -4755,15 +4739,6 @@ qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
         goto cleanup;
     }

-    /* check if hotplug has failed */
-    if (vcpus < oldvcpus && ncpupids == oldvcpus) {
-        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                       _("qemu didn't unplug the vCPUs properly"));
-        vcpus = oldvcpus;
-        ret = -1;
-        goto cleanup;
-    }
-
     if (ncpupids != vcpus) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("got wrong number of vCPU pids from QEMU monitor. "
@@ -4781,50 +4756,37 @@ qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
                                             &mem_mask, -1) < 0)
         goto cleanup;

-    if (nvcpus > oldvcpus) {
-        for (i = oldvcpus; i < nvcpus; i++) {
-            if (priv->cgroup) {
-                cgroup_vcpu =
-                    qemuDomainAddCgroupForThread(priv->cgroup,
-                                                 VIR_CGROUP_THREAD_VCPU,
-                                                 i, mem_mask,
-                                                 cpupids[i]);
-                if (!cgroup_vcpu)
-                    goto cleanup;
-            }
+    for (i = oldvcpus; i < nvcpus; i++) {
+        if (priv->cgroup) {
+            cgroup_vcpu =
+                qemuDomainAddCgroupForThread(priv->cgroup,
+                                             VIR_CGROUP_THREAD_VCPU,
+                                             i, mem_mask,
+                                             cpupids[i]);
+            if (!cgroup_vcpu)
+                goto cleanup;
+        }

-            /* Inherit def->cpuset */
-            if (vm->def->cpumask) {
-                if (qemuDomainHotplugAddPin(vm->def->cpumask, i,
-                                            &vm->def->cputune.vcpupin,
-                                            &vm->def->cputune.nvcpupin) < 0) {
-                    ret = -1;
-                    goto cleanup;
-                }
-                if (qemuDomainHotplugPinThread(vm->def->cpumask, i, cpupids[i],
-                                               cgroup_vcpu) < 0) {
-                    ret = -1;
-                    goto cleanup;
-                }
+        /* Inherit def->cpuset */
+        if (vm->def->cpumask) {
+            if (qemuDomainHotplugAddPin(vm->def->cpumask, i,
+                                        &vm->def->cputune.vcpupin,
+                                        &vm->def->cputune.nvcpupin) < 0) {
+                ret = -1;
+                goto cleanup;
             }
-            virCgroupFree(&cgroup_vcpu);
-
-            if (qemuProcessSetSchedParams(i, cpupids[i],
-                                          vm->def->cputune.nvcpusched,
-                                          vm->def->cputune.vcpusched) < 0)
+            if (qemuDomainHotplugPinThread(vm->def->cpumask, i, cpupids[i],
+                                           cgroup_vcpu) < 0) {
+                ret = -1;
                 goto cleanup;
+            }
         }
-    } else {
-        for (i = oldvcpus - 1; i >= nvcpus; i--) {
-            if (qemuDomainDelCgroupForThread(priv->cgroup,
-                                             VIR_CGROUP_THREAD_VCPU, i) < 0)
-                goto cleanup;
+        virCgroupFree(&cgroup_vcpu);

-            /* Free vcpupin setting */
-            virDomainPinDel(&vm->def->cputune.vcpupin,
-                            &vm->def->cputune.nvcpupin,
-                            i);
-        }
+        if (qemuProcessSetSchedParams(i, cpupids[i],
+                                      vm->def->cputune.nvcpusched,
+                                      vm->def->cputune.vcpusched) < 0)
+            goto cleanup;
     }

     priv->nvcpupids = ncpupids;
@@ -4853,6 +4815,101 @@ qemuDomainHotplugVcpus(virQEMUDriverPtr driver,


 static int
+qemuDomainHotunplugVcpus(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm,
+                         unsigned int nvcpus)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    size_t i;
+    int rc = 1;
+    int ret = -1;
+    int oldvcpus = virDomainDefGetVCpus(vm->def);
+    int vcpus = oldvcpus;
+    pid_t *cpupids = NULL;
+    int ncpupids;
+
+    qemuDomainObjEnterMonitor(driver, vm);
+
+    for (i = vcpus - 1; i >= nvcpus; i--) {
+        /* Offline old CPU */
+        rc = qemuMonitorSetCPU(priv->mon, i, false);
+        if (rc == 0)
+            goto unsupported;
+        if (rc < 0)
+            goto exit_monitor;
+
+        vcpus--;
+    }
+
+    ret = 0;
+
+    /* After hotplugging the CPUs we need to re-detect threads corresponding
+     * to the virtual CPUs. Some older versions don't provide the thread ID
+     * or don't have the "info cpus" command (and they don't support multiple
+     * CPUs anyways), so errors in the re-detection will not be treated
+     * fatal */
+    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) <= 0) {
+        virResetLastError();
+        goto exit_monitor;
+    }
+    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
+        ret = -1;
+        goto cleanup;
+    }
+
+    /* check if hotunplug has failed */
+    if (ncpupids == oldvcpus) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("qemu didn't unplug the vCPUs properly"));
+        vcpus = oldvcpus;
+        ret = -1;
+        goto cleanup;
+    }
+
+    if (ncpupids != vcpus) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("got wrong number of vCPU pids from QEMU monitor. "
+                         "got %d, wanted %d"),
+                       ncpupids, vcpus);
+        vcpus = oldvcpus;
+        ret = -1;
+        goto cleanup;
+    }
+
+    for (i = oldvcpus - 1; i >= nvcpus; i--) {
+        if (qemuDomainDelCgroupForThread(priv->cgroup,
+                                         VIR_CGROUP_THREAD_VCPU, i) < 0)
+            goto cleanup;
+
+        /* Free vcpupin setting */
+        virDomainPinDel(&vm->def->cputune.vcpupin,
+                        &vm->def->cputune.nvcpupin,
+                        i);
+    }
+
+    priv->nvcpupids = ncpupids;
+    VIR_FREE(priv->vcpupids);
+    priv->vcpupids = cpupids;
+    cpupids = NULL;
+
+ cleanup:
+    VIR_FREE(cpupids);
+    if (virDomainObjIsActive(vm) &&
+        virDomainDefSetVCpus(vm->def, vcpus) < 0)
+        ret = -1;
+    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
+    return ret;
+
+ unsupported:
+    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                   _("cannot change vcpu count of this domain"));
+ exit_monitor:
+    ignore_value(qemuDomainObjExitMonitor(driver, vm));
+    goto cleanup;
+}
+
+
+static int
 qemuDomainSetVcpusAgent(virDomainObjPtr vm,
                         unsigned int nvcpus)
 {
@@ -4985,8 +5042,13 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     }

     if (def) {
-        if (qemuDomainHotplugVcpus(driver, vm, nvcpus) < 0)
-            goto endjob;
+        if (nvcpus > virDomainDefGetVCpus(def)) {
+            if (qemuDomainHotplugVcpus(driver, vm, nvcpus) < 0)
+                goto endjob;
+        } else {
+            if (qemuDomainHotunplugVcpus(driver, vm, nvcpus) < 0)
+                goto endjob;
+        }

         if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
             goto endjob;
-- 
2.6.2




More information about the libvir-list mailing list