[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