[libvirt] [PATCH v2 21/23] qemu: Use mondern vcpu hotplug approach if possible
John Ferlan
jferlan at redhat.com
Sat Aug 20 12:38:12 UTC 2016
$SUBJ: s/mondern/modern
On 08/19/2016 10:38 AM, Peter Krempa wrote:
> To allow unplugging the vcpus, hotplugging of vcpus on platforms which
> require to plug multiple logical vcpus at once or pluging them in in
s/pluging/plugging
s/in in/in an/
> arbitrary order it's necessary to use the new device_add interface for
> vcpu hotplug.
>
> This patch adds support for the device_add interface using the old
> setvcpus API by implementing an algorihm to select the appropriate
s/algorihm/algorithm
> entities to plug in.
> ---
> src/qemu/qemu_driver.c | 155 +++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 138 insertions(+), 17 deletions(-)
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index d083e46..2f88d23 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -4594,46 +4594,66 @@ qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
> virDomainObjPtr vm,
> unsigned int vcpu)
> {
> - qemuDomainObjPrivatePtr priv = vm->privateData;
> + 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 (vcpuinfo->online) {
> - virReportError(VIR_ERR_INVALID_ARG,
> - _("vCPU '%u' is already online"), vcpu);
> - return -1;
> + if (newhotplug) {
> + if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
> + goto cleanup;
Right - need to fill this in with something since it would be empty due
to qom_path not having /vcpu# when initially queried, but now I wonder
will we "overwrite" this...
qemuMonitorJSONProcessHotpluggableCpusReply will generate new ->alias
and qemuMonitorGetCPUInfo will VIR_FREE before stealing...
So nope... But had to go through the process ;-)
> +
> + if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
> + goto cleanup;
> }
>
> qemuDomainObjEnterMonitor(driver, vm);
>
> - rc = qemuMonitorSetCPU(priv->mon, vcpu, true);
> + 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 + 1, "update", rc == 0);
> + virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);
>
> if (rc < 0)
> goto cleanup;
>
> - vcpuinfo->online = true;
> + /* start outputing of the new XML element to allow keeping unpluggability */
outputting
> + if (newhotplug)
> + vm->def->individualvcpus = true;
>
> if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
> goto cleanup;
>
> - if (qemuDomainValidateVcpuInfo(vm) < 0)
> - goto cleanup;
Like qemuDomainRemoveVcpu will "eventually" have - a comment...
/* 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, vcpu) < 0)
> + if (vcpupriv->tid > 0 &&
> + qemuProcessSetupVcpu(vm, i) < 0)
> + goto cleanup;
> + }
> +
> + if (qemuDomainValidateVcpuInfo(vm) < 0)
> goto cleanup;
>
> ret = 0;
>
> cleanup:
> + virJSONValueFree(vcpuprops);
> return ret;
> }
>
> @@ -4771,6 +4791,95 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver,
> }
>
>
> +/**
> + * qemuDomainSelectHotplugVcpuEntities:
> + *
> + * @def: domain definition
> + * @nvcpus: target vcpu count
> + * @cpumap: vcpu entity IDs filled on success
> + *
> + * 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.
> + */
> +static virBitmapPtr
> +qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def,
> + unsigned int nvcpus)
> +{
> + virBitmapPtr ret = NULL;
> + virDomainVcpuDefPtr vcpu;
> + qemuDomainVcpuPrivatePtr vcpupriv;
> + unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
> + unsigned int curvcpus = virDomainDefGetVcpus(def);
> + ssize_t i;
> +
Is there an optimization if "nvcpus == curvcpus")?
John
> + if (!(ret = virBitmapNew(maxvcpus)))
> + return NULL;
> +
> + if (nvcpus > curvcpus) {
> + 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 {
> + 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,
> @@ -4784,8 +4893,14 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
> char *all_nodes_str = NULL;
> virBitmapPtr all_nodes = NULL;
> virErrorPtr err = NULL;
> + virBitmapPtr vcpumap = NULL;
> + ssize_t nextvcpu = -1;
> + int rc = 0;
> int ret = -1;
>
> + if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus)))
> + goto cleanup;
> +
> if (virNumaIsAvailable() &&
> virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
> if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0,
> @@ -4804,20 +4919,25 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
> }
>
> if (nvcpus > virDomainDefGetVcpus(vm->def)) {
> - for (i = virDomainDefGetVcpus(vm->def); i < nvcpus; i++) {
> - if (qemuDomainHotplugAddVcpu(driver, vm, i) < 0)
> - goto cleanup;
> + while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
> + if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0)
> + break;
> }
> } else {
> for (i = virDomainDefGetVcpus(vm->def) - 1; i >= nvcpus; i--) {
> - if (qemuDomainHotplugDelVcpu(driver, vm, i) < 0)
> - goto cleanup;
> + if ((rc = qemuDomainHotplugDelVcpu(driver, vm, i)) < 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:
> @@ -4832,6 +4952,7 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
> VIR_FREE(all_nodes_str);
> virBitmapFree(all_nodes);
> virCgroupFree(&cgroup_temp);
> + virBitmapFree(vcpumap);
>
> return ret;
> }
>
More information about the libvir-list
mailing list