mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 12:35:17 +00:00
qemu: Split up vCPU hotplug and hotunplug
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.
This commit is contained in:
parent
2642a36db5
commit
bb1d8d7a84
@ -4692,9 +4692,9 @@ qemuDomainDelCgroupForThread(virCgroupPtr cgroup,
|
||||
}
|
||||
|
||||
static int
|
||||
qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int nvcpus)
|
||||
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int nvcpus)
|
||||
{
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
size_t i;
|
||||
@ -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;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
virCgroupFree(&cgroup_vcpu);
|
||||
|
||||
if (qemuProcessSetSchedParams(i, cpupids[i],
|
||||
vm->def->cputune.nvcpusched,
|
||||
vm->def->cputune.vcpusched) < 0)
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
virCgroupFree(&cgroup_vcpu);
|
||||
|
||||
if (qemuProcessSetSchedParams(i, cpupids[i],
|
||||
vm->def->cputune.nvcpusched,
|
||||
vm->def->cputune.vcpusched) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
priv->nvcpupids = ncpupids;
|
||||
@ -4852,6 +4814,101 @@ qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuDomainHotplugDelVcpu(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 (qemuDomainHotplugAddVcpu(driver, vm, nvcpus) < 0)
|
||||
goto endjob;
|
||||
} else {
|
||||
if (qemuDomainHotplugDelVcpu(driver, vm, nvcpus) < 0)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
||||
goto endjob;
|
||||
|
Loading…
x
Reference in New Issue
Block a user