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
|
||||
qemuDomainSetVcpusAgent(virDomainObjPtr vm,
|
||||
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
|
||||
qemuDomainSetVcpusFlags(virDomainPtr dom,
|
||||
unsigned int nvcpus,
|
||||
|
@ -5346,3 +5346,342 @@ qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
|
||||
|
||||
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,
|
||||
qemuDomainUnpluggingDeviceStatus status);
|
||||
|
||||
int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDefPtr def,
|
||||
virDomainDefPtr persistentDef,
|
||||
unsigned int nvcpus,
|
||||
bool hotpluggable);
|
||||
|
||||
#endif /* __QEMU_HOTPLUG_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user