qemu: Implement individual vcpu hotplug API

Add code that validates user's selection of cores and then uses the
existing code to plug in the vCPU.
This commit is contained in:
Peter Krempa 2016-06-21 17:17:41 +02:00
parent f0326d6dd9
commit f557b3351e
3 changed files with 234 additions and 0 deletions

View File

@ -20210,6 +20210,79 @@ qemuDomainSetGuestVcpus(virDomainPtr dom,
}
static int
qemuDomainSetVcpu(virDomainPtr dom,
const char *cpumap,
int state,
unsigned int flags)
{
virQEMUDriverPtr driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
virDomainDefPtr def = NULL;
virDomainDefPtr persistentDef = NULL;
virBitmapPtr map = NULL;
ssize_t lastvcpu;
int ret = -1;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG, -1);
if (state != 0 && state != 1) {
virReportInvalidArg(state, "%s", _("unsupported state value"));
return -1;
}
if (virBitmapParse(cpumap, &map, QEMU_GUEST_VCPU_MAX_ID) < 0)
goto cleanup;
if ((lastvcpu = virBitmapLastSetBit(map)) < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("no vcpus selected for modification"));
goto cleanup;
}
if (!(vm = qemuDomObjFromDomain(dom)))
goto cleanup;
if (virDomainSetVcpuEnsureACL(dom->conn, vm->def, flags) < 0)
goto cleanup;
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
goto endjob;
if (persistentDef) {
if (lastvcpu >= virDomainDefGetVcpusMax(persistentDef)) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu %zd is not present in persistent config"),
lastvcpu);
goto endjob;
}
}
if (def) {
if (lastvcpu >= virDomainDefGetVcpusMax(def)) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu %zd is not present in live config"),
lastvcpu);
goto endjob;
}
}
ret = qemuDomainSetVcpuInternal(driver, vm, def, persistentDef, map, !!state);
endjob:
qemuDomainObjEndJob(driver, vm);
cleanup:
virBitmapFree(map);
virDomainObjEndAPI(&vm);
return ret;
}
static virHypervisorDriver qemuHypervisorDriver = {
.name = QEMU_DRIVER_NAME,
.connectOpen = qemuConnectOpen, /* 0.2.0 */
@ -20423,6 +20496,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
.domainMigrateStartPostCopy = qemuDomainMigrateStartPostCopy, /* 1.3.3 */
.domainGetGuestVcpus = qemuDomainGetGuestVcpus, /* 2.0.0 */
.domainSetGuestVcpus = qemuDomainSetGuestVcpus, /* 2.0.0 */
.domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */
};

View File

@ -5700,3 +5700,156 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
virObjectUnref(cfg);
return ret;
}
static void
qemuDomainSetVcpuConfig(virDomainDefPtr def,
virBitmapPtr map,
bool state)
{
virDomainVcpuDefPtr vcpu;
ssize_t next = -1;
def->individualvcpus = true;
while ((next = virBitmapNextSetBit(map, next)) > 0) {
if (!(vcpu = virDomainDefGetVcpu(def, next)))
continue;
vcpu->online = state;
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
vcpu->order = 0;
}
}
/**
* qemuDomainFilterHotplugVcpuEntities:
*
* Returns a bitmap of hotpluggable vcpu entities that correspond to the logical
* vcpus requested in @vcpus.
*/
static virBitmapPtr
qemuDomainFilterHotplugVcpuEntities(virDomainDefPtr def,
virBitmapPtr vcpus,
bool state)
{
qemuDomainVcpuPrivatePtr vcpupriv;
virDomainVcpuDefPtr vcpu;
virBitmapPtr map = NULL;
virBitmapPtr ret = NULL;
ssize_t next = -1;
size_t i;
if (!(map = virBitmapNewCopy(vcpus)))
return NULL;
/* make sure that all selected vcpus are in the correct state */
while ((next = virBitmapNextSetBit(map, next)) > 0) {
if (!(vcpu = virDomainDefGetVcpu(def, next)))
continue;
if (vcpu->online == state) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu '%zu' is already in requested state"), next);
goto cleanup;
}
if (vcpu->online && !vcpu->hotpluggable) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu '%zu' can't be hotunplugged"), next);
goto cleanup;
}
}
/* Make sure that all vCPUs belonging to a single hotpluggable entity were
* selected and then de-select any sub-threads of it. */
next = -1;
while ((next = virBitmapNextSetBit(map, next)) > 0) {
if (!(vcpu = virDomainDefGetVcpu(def, next)))
continue;
vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);
if (vcpupriv->vcpus == 0) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu '%zu' belongs to a larger hotpluggable entity, "
"but siblings were not selected"), next);
goto cleanup;
}
for (i = next + 1; i < next + vcpupriv->vcpus; i++) {
if (!virBitmapIsBitSet(map, i)) {
virReportError(VIR_ERR_INVALID_ARG,
_("vcpu '%zu' was not selected but it belongs to "
"hotpluggable entity '%zu-%zu' which was "
"partially selected"),
i, next, next + vcpupriv->vcpus - 1);
goto cleanup;
}
/* clear the subthreads */
ignore_value(virBitmapClearBit(map, i));
}
}
VIR_STEAL_PTR(ret, map);
cleanup:
virBitmapFree(map);
return ret;
}
int
qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDefPtr def,
virDomainDefPtr persistentDef,
virBitmapPtr map,
bool state)
{
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virBitmapPtr livevcpus = NULL;
int ret = -1;
if (def) {
if (!qemuDomainSupportsNewVcpuHotplug(vm)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("this qemu version does not support specific "
"vCPU hotplug"));
goto cleanup;
}
if (!(livevcpus = qemuDomainFilterHotplugVcpuEntities(def, map, state)))
goto cleanup;
/* Make sure that only one hotpluggable entity is selected.
* qemuDomainSetVcpusLive allows setting more at once but error
* resolution in case of a partial failure is hard, so don't let users
* do so */
if (virBitmapCountBits(livevcpus) != 1) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("only one hotpluggable entity can be selected"));
goto cleanup;
}
}
if (livevcpus &&
qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0)
goto cleanup;
if (persistentDef) {
qemuDomainSetVcpuConfig(persistentDef, map, state);
if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
goto cleanup;
}
ret = 0;
cleanup:
virBitmapFree(livevcpus);
virObjectUnref(cfg);
return ret;
}

View File

@ -143,4 +143,11 @@ int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
unsigned int nvcpus,
bool hotpluggable);
int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDefPtr def,
virDomainDefPtr persistentDef,
virBitmapPtr vcpus,
bool state);
#endif /* __QEMU_HOTPLUG_H__ */