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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list