Add code that validates user's selection of cores and then uses the existing code to plug in the vCPU. --- src/qemu/qemu_driver.c | 74 +++++++++++++++++++++++ src/qemu/qemu_hotplug.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 7 +++ 3 files changed, 234 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 89bc833de..2b875b3e9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20190,6 +20190,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 */ @@ -20403,6 +20476,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainMigrateStartPostCopy = qemuDomainMigrateStartPostCopy, /* 1.3.3 */ .domainGetGuestVcpus = qemuDomainGetGuestVcpus, /* 2.0.0 */ .domainSetGuestVcpus = qemuDomainSetGuestVcpus, /* 2.0.0 */ + .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */ }; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 2f209f12b..363d1070b 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5700,3 +5700,156 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, virObjectUnref(cfg); return ret; } + + +static void +qemuDomainSetVcpuInactive(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) { + qemuDomainSetVcpuInactive(persistentDef, map, state); + + if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virBitmapFree(livevcpus); + virObjectUnref(cfg); + return ret; +} diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 13242eec9..0b11c1ed9 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -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__ */ -- 2.11.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list