mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
qemu: Move cpu hotplug code into qemu_hotplug.c
Move all the worker code into the appropriate file. This will also allow testing of cpu hotplug.
This commit is contained in:
parent
5570f26763
commit
9d14cf595a
@ -4615,76 +4615,6 @@ static void qemuProcessEventHandler(void *data, void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
|
|
||||||
virDomainObjPtr vm,
|
|
||||||
unsigned int vcpu)
|
|
||||||
{
|
|
||||||
virJSONValuePtr vcpuprops = NULL;
|
|
||||||
virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
|
|
||||||
qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
|
||||||
unsigned int nvcpus = vcpupriv->vcpus;
|
|
||||||
bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm);
|
|
||||||
int ret = -1;
|
|
||||||
int rc;
|
|
||||||
int oldvcpus = virDomainDefGetVcpus(vm->def);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (newhotplug) {
|
|
||||||
if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuDomainObjEnterMonitor(driver, vm);
|
|
||||||
|
|
||||||
if (newhotplug) {
|
|
||||||
rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops);
|
|
||||||
vcpuprops = NULL;
|
|
||||||
} else {
|
|
||||||
rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);
|
|
||||||
|
|
||||||
if (rc < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* start outputting of the new XML element to allow keeping unpluggability */
|
|
||||||
if (newhotplug)
|
|
||||||
vm->def->individualvcpus = true;
|
|
||||||
|
|
||||||
if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* validation requires us to set the expected state prior to calling it */
|
|
||||||
for (i = vcpu; i < vcpu + nvcpus; i++) {
|
|
||||||
vcpuinfo = virDomainDefGetVcpu(vm->def, i);
|
|
||||||
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
|
||||||
|
|
||||||
vcpuinfo->online = true;
|
|
||||||
|
|
||||||
if (vcpupriv->tid > 0 &&
|
|
||||||
qemuProcessSetupVcpu(vm, i) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qemuDomainValidateVcpuInfo(vm) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
virJSONValueFree(vcpuprops);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuDomainSetVcpusAgent(virDomainObjPtr vm,
|
qemuDomainSetVcpusAgent(virDomainObjPtr vm,
|
||||||
unsigned int nvcpus)
|
unsigned int nvcpus)
|
||||||
@ -4779,275 +4709,6 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* qemuDomainSelectHotplugVcpuEntities:
|
|
||||||
*
|
|
||||||
* @def: domain definition
|
|
||||||
* @nvcpus: target vcpu count
|
|
||||||
* @enable: set to true if vcpus should be enabled
|
|
||||||
*
|
|
||||||
* Tries to find which vcpu entities need to be enabled or disabled to reach
|
|
||||||
* @nvcpus. This function works in order of the legacy hotplug but is able to
|
|
||||||
* skip over entries that are added out of order.
|
|
||||||
*
|
|
||||||
* Returns the bitmap of vcpus to modify on success, NULL on error.
|
|
||||||
*/
|
|
||||||
static virBitmapPtr
|
|
||||||
qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def,
|
|
||||||
unsigned int nvcpus,
|
|
||||||
bool *enable)
|
|
||||||
{
|
|
||||||
virBitmapPtr ret = NULL;
|
|
||||||
virDomainVcpuDefPtr vcpu;
|
|
||||||
qemuDomainVcpuPrivatePtr vcpupriv;
|
|
||||||
unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
|
|
||||||
unsigned int curvcpus = virDomainDefGetVcpus(def);
|
|
||||||
ssize_t i;
|
|
||||||
|
|
||||||
if (!(ret = virBitmapNew(maxvcpus)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (nvcpus > curvcpus) {
|
|
||||||
*enable = true;
|
|
||||||
|
|
||||||
for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) {
|
|
||||||
vcpu = virDomainDefGetVcpu(def, i);
|
|
||||||
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
|
||||||
|
|
||||||
if (vcpu->online)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (vcpupriv->vcpus == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
curvcpus += vcpupriv->vcpus;
|
|
||||||
|
|
||||||
if (curvcpus > nvcpus) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
||||||
_("target vm vcpu granularity does not allow the "
|
|
||||||
"desired vcpu count"));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ignore_value(virBitmapSetBit(ret, i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*enable = false;
|
|
||||||
|
|
||||||
for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) {
|
|
||||||
vcpu = virDomainDefGetVcpu(def, i);
|
|
||||||
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
|
||||||
|
|
||||||
if (!vcpu->online)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (vcpupriv->vcpus == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!vcpupriv->alias)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
curvcpus -= vcpupriv->vcpus;
|
|
||||||
|
|
||||||
if (curvcpus < nvcpus) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
||||||
_("target vm vcpu granularity does not allow the "
|
|
||||||
"desired vcpu count"));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ignore_value(virBitmapSetBit(ret, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curvcpus != nvcpus) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
||||||
_("failed to find appropriate hotpluggable vcpus to "
|
|
||||||
"reach the desired target vcpu count"));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
virBitmapFree(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
|
||||||
virQEMUDriverConfigPtr cfg,
|
|
||||||
virDomainObjPtr vm,
|
|
||||||
virBitmapPtr vcpumap,
|
|
||||||
bool enable)
|
|
||||||
{
|
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
||||||
qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL;
|
|
||||||
ssize_t nextvcpu = -1;
|
|
||||||
int rc = 0;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
|
|
||||||
if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
|
|
||||||
if (!virBitmapIsBitSet(vcpumap, nextvcpu))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuDomainVcpuPersistOrder(vm->def);
|
|
||||||
|
|
||||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (rc < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
qemuCgroupEmulatorAllNodesRestore(emulatorCgroup);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* qemuDomainSetVcpusConfig:
|
|
||||||
* @def: config/offline definition of a domain
|
|
||||||
* @nvcpus: target vcpu count
|
|
||||||
*
|
|
||||||
* Properly handle cold(un)plug of vcpus:
|
|
||||||
* - plug in inactive vcpus/uplug active rather than rewriting state
|
|
||||||
* - fix hotpluggable state
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
qemuDomainSetVcpusConfig(virDomainDefPtr def,
|
|
||||||
unsigned int nvcpus,
|
|
||||||
bool hotpluggable)
|
|
||||||
{
|
|
||||||
virDomainVcpuDefPtr vcpu;
|
|
||||||
size_t curvcpus = virDomainDefGetVcpus(def);
|
|
||||||
size_t maxvcpus = virDomainDefGetVcpusMax(def);
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* ordering information may become invalid, thus clear it */
|
|
||||||
virDomainDefVcpuOrderClear(def);
|
|
||||||
|
|
||||||
if (curvcpus == nvcpus)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (curvcpus < nvcpus) {
|
|
||||||
for (i = 0; i < maxvcpus; i++) {
|
|
||||||
vcpu = virDomainDefGetVcpu(def, i);
|
|
||||||
|
|
||||||
if (!vcpu)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (vcpu->online) {
|
|
||||||
/* non-hotpluggable vcpus need to be clustered at the beggining,
|
|
||||||
* thus we need to force vcpus to be hotpluggable when we find
|
|
||||||
* vcpus that are hotpluggable and online prior to the ones
|
|
||||||
* we are going to add */
|
|
||||||
if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES)
|
|
||||||
hotpluggable = true;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vcpu->online = true;
|
|
||||||
if (hotpluggable) {
|
|
||||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
|
||||||
def->individualvcpus = true;
|
|
||||||
} else {
|
|
||||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++curvcpus == nvcpus)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i = maxvcpus; i != 0; i--) {
|
|
||||||
vcpu = virDomainDefGetVcpu(def, i - 1);
|
|
||||||
|
|
||||||
if (!vcpu || !vcpu->online)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vcpu->online = false;
|
|
||||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
|
||||||
|
|
||||||
if (--curvcpus == nvcpus)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
|
|
||||||
virDomainObjPtr vm,
|
|
||||||
virDomainDefPtr def,
|
|
||||||
virDomainDefPtr persistentDef,
|
|
||||||
unsigned int nvcpus,
|
|
||||||
bool hotpluggable)
|
|
||||||
{
|
|
||||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
||||||
virBitmapPtr vcpumap = NULL;
|
|
||||||
bool enable;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (def && nvcpus > virDomainDefGetVcpusMax(def)) {
|
|
||||||
virReportError(VIR_ERR_INVALID_ARG,
|
|
||||||
_("requested vcpus is greater than max allowable"
|
|
||||||
" vcpus for the live domain: %u > %u"),
|
|
||||||
nvcpus, virDomainDefGetVcpusMax(def));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) {
|
|
||||||
virReportError(VIR_ERR_INVALID_ARG,
|
|
||||||
_("requested vcpus is greater than max allowable"
|
|
||||||
" vcpus for the persistent domain: %u > %u"),
|
|
||||||
nvcpus, virDomainDefGetVcpusMax(persistentDef));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (def) {
|
|
||||||
if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus,
|
|
||||||
&enable)))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (persistentDef) {
|
|
||||||
qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable);
|
|
||||||
|
|
||||||
if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
virBitmapFree(vcpumap);
|
|
||||||
virObjectUnref(cfg);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuDomainSetVcpusFlags(virDomainPtr dom,
|
qemuDomainSetVcpusFlags(virDomainPtr dom,
|
||||||
unsigned int nvcpus,
|
unsigned int nvcpus,
|
||||||
|
@ -5346,3 +5346,342 @@ qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
|
|||||||
|
|
||||||
return qemuDomainRemoveVcpu(driver, vm, vcpu);
|
return qemuDomainRemoveVcpu(driver, vm, vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned int vcpu)
|
||||||
|
{
|
||||||
|
virJSONValuePtr vcpuprops = NULL;
|
||||||
|
virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
|
||||||
|
qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
||||||
|
unsigned int nvcpus = vcpupriv->vcpus;
|
||||||
|
bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm);
|
||||||
|
int ret = -1;
|
||||||
|
int rc;
|
||||||
|
int oldvcpus = virDomainDefGetVcpus(vm->def);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (newhotplug) {
|
||||||
|
if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemuDomainObjEnterMonitor(driver, vm);
|
||||||
|
|
||||||
|
if (newhotplug) {
|
||||||
|
rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops);
|
||||||
|
vcpuprops = NULL;
|
||||||
|
} else {
|
||||||
|
rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* start outputting of the new XML element to allow keeping unpluggability */
|
||||||
|
if (newhotplug)
|
||||||
|
vm->def->individualvcpus = true;
|
||||||
|
|
||||||
|
if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* validation requires us to set the expected state prior to calling it */
|
||||||
|
for (i = vcpu; i < vcpu + nvcpus; i++) {
|
||||||
|
vcpuinfo = virDomainDefGetVcpu(vm->def, i);
|
||||||
|
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
|
||||||
|
|
||||||
|
vcpuinfo->online = true;
|
||||||
|
|
||||||
|
if (vcpupriv->tid > 0 &&
|
||||||
|
qemuProcessSetupVcpu(vm, i) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainValidateVcpuInfo(vm) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virJSONValueFree(vcpuprops);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuDomainSelectHotplugVcpuEntities:
|
||||||
|
*
|
||||||
|
* @def: domain definition
|
||||||
|
* @nvcpus: target vcpu count
|
||||||
|
* @enable: set to true if vcpus should be enabled
|
||||||
|
*
|
||||||
|
* Tries to find which vcpu entities need to be enabled or disabled to reach
|
||||||
|
* @nvcpus. This function works in order of the legacy hotplug but is able to
|
||||||
|
* skip over entries that are added out of order.
|
||||||
|
*
|
||||||
|
* Returns the bitmap of vcpus to modify on success, NULL on error.
|
||||||
|
*/
|
||||||
|
static virBitmapPtr
|
||||||
|
qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def,
|
||||||
|
unsigned int nvcpus,
|
||||||
|
bool *enable)
|
||||||
|
{
|
||||||
|
virBitmapPtr ret = NULL;
|
||||||
|
virDomainVcpuDefPtr vcpu;
|
||||||
|
qemuDomainVcpuPrivatePtr vcpupriv;
|
||||||
|
unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
|
||||||
|
unsigned int curvcpus = virDomainDefGetVcpus(def);
|
||||||
|
ssize_t i;
|
||||||
|
|
||||||
|
if (!(ret = virBitmapNew(maxvcpus)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (nvcpus > curvcpus) {
|
||||||
|
*enable = true;
|
||||||
|
|
||||||
|
for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) {
|
||||||
|
vcpu = virDomainDefGetVcpu(def, i);
|
||||||
|
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
||||||
|
|
||||||
|
if (vcpu->online)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vcpupriv->vcpus == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
curvcpus += vcpupriv->vcpus;
|
||||||
|
|
||||||
|
if (curvcpus > nvcpus) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("target vm vcpu granularity does not allow the "
|
||||||
|
"desired vcpu count"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore_value(virBitmapSetBit(ret, i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*enable = false;
|
||||||
|
|
||||||
|
for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) {
|
||||||
|
vcpu = virDomainDefGetVcpu(def, i);
|
||||||
|
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
|
||||||
|
|
||||||
|
if (!vcpu->online)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vcpupriv->vcpus == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!vcpupriv->alias)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
curvcpus -= vcpupriv->vcpus;
|
||||||
|
|
||||||
|
if (curvcpus < nvcpus) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("target vm vcpu granularity does not allow the "
|
||||||
|
"desired vcpu count"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore_value(virBitmapSetBit(ret, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curvcpus != nvcpus) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("failed to find appropriate hotpluggable vcpus to "
|
||||||
|
"reach the desired target vcpu count"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
error:
|
||||||
|
virBitmapFree(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
|
||||||
|
virQEMUDriverConfigPtr cfg,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virBitmapPtr vcpumap,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL;
|
||||||
|
ssize_t nextvcpu = -1;
|
||||||
|
int rc = 0;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
|
||||||
|
if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
|
||||||
|
if (!virBitmapIsBitSet(vcpumap, nextvcpu))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qemuDomainVcpuPersistOrder(vm->def);
|
||||||
|
|
||||||
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
qemuCgroupEmulatorAllNodesRestore(emulatorCgroup);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuDomainSetVcpusConfig:
|
||||||
|
* @def: config/offline definition of a domain
|
||||||
|
* @nvcpus: target vcpu count
|
||||||
|
*
|
||||||
|
* Properly handle cold(un)plug of vcpus:
|
||||||
|
* - plug in inactive vcpus/uplug active rather than rewriting state
|
||||||
|
* - fix hotpluggable state
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
qemuDomainSetVcpusConfig(virDomainDefPtr def,
|
||||||
|
unsigned int nvcpus,
|
||||||
|
bool hotpluggable)
|
||||||
|
{
|
||||||
|
virDomainVcpuDefPtr vcpu;
|
||||||
|
size_t curvcpus = virDomainDefGetVcpus(def);
|
||||||
|
size_t maxvcpus = virDomainDefGetVcpusMax(def);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* ordering information may become invalid, thus clear it */
|
||||||
|
virDomainDefVcpuOrderClear(def);
|
||||||
|
|
||||||
|
if (curvcpus == nvcpus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (curvcpus < nvcpus) {
|
||||||
|
for (i = 0; i < maxvcpus; i++) {
|
||||||
|
vcpu = virDomainDefGetVcpu(def, i);
|
||||||
|
|
||||||
|
if (!vcpu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vcpu->online) {
|
||||||
|
/* non-hotpluggable vcpus need to be clustered at the beggining,
|
||||||
|
* thus we need to force vcpus to be hotpluggable when we find
|
||||||
|
* vcpus that are hotpluggable and online prior to the ones
|
||||||
|
* we are going to add */
|
||||||
|
if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES)
|
||||||
|
hotpluggable = true;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcpu->online = true;
|
||||||
|
if (hotpluggable) {
|
||||||
|
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
||||||
|
def->individualvcpus = true;
|
||||||
|
} else {
|
||||||
|
vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++curvcpus == nvcpus)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = maxvcpus; i != 0; i--) {
|
||||||
|
vcpu = virDomainDefGetVcpu(def, i - 1);
|
||||||
|
|
||||||
|
if (!vcpu || !vcpu->online)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vcpu->online = false;
|
||||||
|
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
||||||
|
|
||||||
|
if (--curvcpus == nvcpus)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDefPtr def,
|
||||||
|
virDomainDefPtr persistentDef,
|
||||||
|
unsigned int nvcpus,
|
||||||
|
bool hotpluggable)
|
||||||
|
{
|
||||||
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||||
|
virBitmapPtr vcpumap = NULL;
|
||||||
|
bool enable;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (def && nvcpus > virDomainDefGetVcpusMax(def)) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("requested vcpus is greater than max allowable"
|
||||||
|
" vcpus for the live domain: %u > %u"),
|
||||||
|
nvcpus, virDomainDefGetVcpusMax(def));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("requested vcpus is greater than max allowable"
|
||||||
|
" vcpus for the persistent domain: %u > %u"),
|
||||||
|
nvcpus, virDomainDefGetVcpusMax(persistentDef));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def) {
|
||||||
|
if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus,
|
||||||
|
&enable)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (persistentDef) {
|
||||||
|
qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable);
|
||||||
|
|
||||||
|
if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virBitmapFree(vcpumap);
|
||||||
|
virObjectUnref(cfg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -136,4 +136,11 @@ bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
|
|||||||
const char *devAlias,
|
const char *devAlias,
|
||||||
qemuDomainUnpluggingDeviceStatus status);
|
qemuDomainUnpluggingDeviceStatus status);
|
||||||
|
|
||||||
|
int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDefPtr def,
|
||||||
|
virDomainDefPtr persistentDef,
|
||||||
|
unsigned int nvcpus,
|
||||||
|
bool hotpluggable);
|
||||||
|
|
||||||
#endif /* __QEMU_HOTPLUG_H__ */
|
#endif /* __QEMU_HOTPLUG_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user