[libvirt] [PATCH 19/34] qemu: Split up vCPU hotplug and hotunplug
John Ferlan
jferlan at redhat.com
Mon Nov 23 19:19:58 UTC 2015
On 11/20/2015 10:22 AM, Peter Krempa wrote:
> 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 */
I originally though it might have be nice to carry this comment in the
unplug - just to understand why going in reverse order was chosen, but I
see eventually that becomes irrelevant.
> - 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;
> - }
Good thing I peeked ahead one patch ;-) Was going to make a comment
about the ret = -1; logic especially w/r/t how [n]vcpupids is handled.
> + 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;
> + }
Could have gone with HotplugAddVcpus and HotplugDelVcpus (similar to
IOThreads). Whether you change is up to you.
ACK -
John
>
> if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
> goto endjob;
>
More information about the libvir-list
mailing list