[libvirt] [PATCH v5 09/10] qemu: Add support to Add/Delete IOThreads

John Ferlan jferlan at redhat.com
Mon Apr 27 16:08:30 UTC 2015



On 04/27/2015 10:45 AM, Peter Krempa wrote:
> On Fri, Apr 24, 2015 at 12:06:01 -0400, John Ferlan wrote:
>> Add qemuDomainAddIOThread and qemuDomainDelIOThread in order to add or
>> remove an IOThread to/from the host either for live or config optoins
>>
>> The implementation for the 'live' option will use the iothreadpids list
>> in order to make decision, while the 'config' option will use the
>> iothreadids list.  Additionally, for deletion each may have to adjust
>> the iothreadpin list.
>>
>> IOThreads are implemented by qmp objects, the code makes use of the existing
>> qemuMonitorAddObject or qemuMonitorDelObject APIs.
>>
>> Signed-off-by: John Ferlan <jferlan at redhat.com>
>> ---
>>  src/conf/domain_audit.c  |   9 ++
>>  src/conf/domain_audit.h  |   6 +
>>  src/libvirt_private.syms |   1 +
>>  src/qemu/qemu_driver.c   | 380 +++++++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 396 insertions(+)
>>
> 
> ...
> 
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index 1fac0b8..4ae63c6 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -6154,6 +6154,384 @@ qemuDomainPinIOThread(virDomainPtr dom,
>>      return ret;
>>  }
>>  
>> +static int
>> +qemuDomainHotplugAddIOThread(virQEMUDriverPtr driver,
>> +                             virDomainObjPtr vm,
>> +                             unsigned int iothread_id)
>> +{
>> +    qemuDomainObjPrivatePtr priv = vm->privateData;
>> +    char *alias = NULL;
>> +    size_t idx;
>> +    int rc = -1;
>> +    int ret = -1;
>> +    unsigned int orig_niothreads = vm->def->iothreads;
>> +    unsigned int exp_niothreads = vm->def->iothreads;
>> +    int new_niothreads = 0;
>> +    qemuMonitorIOThreadInfoPtr *new_iothreads = NULL;
>> +    virCgroupPtr cgroup_iothread = NULL;
>> +    char *mem_mask = NULL;
>> +    virDomainIOThreadIDDefPtr iothrid;
>> +    virBitmapPtr cpumask;
>> +
>> +    if (virDomainIOThreadIDFind(vm->def, iothread_id)) {
>> +        virReportError(VIR_ERR_INVALID_ARG,
>> +                       _("an IOThread is already using iothread_id '%u'"),
>> +                       iothread_id);
>> +        goto cleanup;
>> +    }
>> +
>> +    if (virAsprintf(&alias, "iothread%u", iothread_id) < 0)
>> +        return -1;
>> +
>> +    qemuDomainObjEnterMonitor(driver, vm);
>> +
>> +    rc = qemuMonitorAddObject(priv->mon, "iothread", alias, NULL);
>> +    exp_niothreads++;
>> +    if (rc < 0)
>> +        goto exit_monitor;
>> +
>> +    /* After hotplugging the IOThreads we need to re-detect the
>> +     * IOThreads thread_id's, adjust the cgroups, thread affinity,
>> +     * and add the thread_id to the vm->def->iothreadids list.
>> +     */
>> +    if ((new_niothreads = qemuMonitorGetIOThreads(priv->mon,
>> +                                                  &new_iothreads)) < 0)
>> +        goto exit_monitor;
>> +
>> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> +        goto cleanup;
>> +
>> +    if (new_niothreads != exp_niothreads) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("got wrong number of IOThread ids from QEMU monitor. "
>> +                         "got %d, wanted %d"),
>> +                       new_niothreads, exp_niothreads);
>> +        vm->def->iothreads = new_niothreads;
>> +        goto cleanup;
>> +    }
>> +    vm->def->iothreads = exp_niothreads;
>> +
>> +    if (virDomainNumatuneGetMode(vm->def->numa, -1) ==
>> +        VIR_DOMAIN_NUMATUNE_MEM_STRICT &&
>> +        virDomainNumatuneMaybeFormatNodeset(vm->def->numa,
>> +                                            priv->autoNodeset,
>> +                                            &mem_mask, -1) < 0)
>> +        goto cleanup;
>> +
>> +
>> +    /*
>> +     * If we've successfully added an IOThread, find out where we added it
>> +     * in the QEMU IOThread list, so we can add it to our iothreadids list
>> +     */
>> +    for (idx = 0; idx < new_niothreads; idx++) {
>> +        if (STREQ(new_iothreads[idx]->name, alias))
>> +            break;
>> +    }
>> +
>> +    if (idx == new_niothreads) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("cannot find new IOThread '%u' in QEMU monitor."),
>> +                       iothread_id);
>> +        goto cleanup;
>> +    }
>> +
>> +    if (!(iothrid = virDomainIOThreadIDAdd(vm->def, iothread_id)))
>> +        goto cleanup;
>> +
>> +    iothrid->thread_id = new_iothreads[idx]->thread_id;
>> +
>> +    /* Add IOThread to cgroup if present */
>> +    if (priv->cgroup) {
>> +        cgroup_iothread =
>> +            qemuDomainAddCgroupForThread(priv->cgroup,
>> +                                         VIR_CGROUP_THREAD_IOTHREAD,
>> +                                         iothread_id, mem_mask,
>> +                                         iothrid->thread_id);
>> +        if (!cgroup_iothread)
>> +            goto cleanup;
>> +    }
>> +
>> +    if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
>> +        cpumask = priv->autoCpuset;
>> +    else
>> +        cpumask = vm->def->cpumask;
>> +
>> +    if (cpumask) {
>> +        if (qemuDomainHotplugPinThread(cpumask, iothread_id,
>> +                                       iothrid->thread_id, cgroup_iothread) < 0)
>> +            goto cleanup;
>> +    }
>> +
>> +    ret = 0;
>> +
>> + cleanup:
>> +    if (new_iothreads) {
>> +        for (idx = 0; idx < new_niothreads; idx++)
>> +            qemuMonitorIOThreadInfoFree(new_iothreads[idx]);
>> +        VIR_FREE(new_iothreads);
>> +    }
>> +    VIR_FREE(mem_mask);
>> +    virDomainAuditIOThread(vm, orig_niothreads, new_niothreads,
>> +                           "update", rc == 0);
>> +    virCgroupFree(&cgroup_iothread);
>> +    VIR_FREE(alias);
>> +    return ret;
>> +
>> + exit_monitor:
>> +    ignore_value(qemuDomainObjExitMonitor(driver, vm));
>> +    goto cleanup;
>> +}
>> +
>> +static int
>> +qemuDomainHotplugDelIOThread(virQEMUDriverPtr driver,
>> +                             virDomainObjPtr vm,
>> +                             unsigned int iothread_id)
>> +{
>> +    qemuDomainObjPrivatePtr priv = vm->privateData;
>> +    size_t idx;
>> +    char *alias = NULL;
>> +    int rc = -1;
>> +    int ret = -1;
>> +    unsigned int orig_niothreads = vm->def->iothreads;
>> +    unsigned int exp_niothreads = vm->def->iothreads;
>> +    int new_niothreads = 0;
>> +    qemuMonitorIOThreadInfoPtr *new_iothreads = NULL;
>> +
>> +    /* Normally would use virDomainIOThreadIDFind, but we need the index
>> +     * from whence to delete for later...
>> +     */
>> +    for (idx = 0; idx < vm->def->niothreadids; idx++) {
>> +        if (iothread_id == vm->def->iothreadids[idx]->iothread_id)
>> +            break;
>> +    }
>> +
>> +    if (idx == vm->def->niothreadids) {
>> +        virReportError(VIR_ERR_INVALID_ARG,
>> +                       _("cannot find IOThread '%u' in iothreadids list"),
>> +                       iothread_id);
>> +        return -1;
>> +    }
>> +
>> +    if (virAsprintf(&alias, "iothread%u", iothread_id) < 0)
>> +        return -1;
>> +
>> +    qemuDomainObjEnterMonitor(driver, vm);
>> +
>> +    rc = qemuMonitorDelObject(priv->mon, alias);
>> +    exp_niothreads--;
>> +    if (rc < 0)
>> +        goto exit_monitor;
>> +
>> +    if ((new_niothreads = qemuMonitorGetIOThreads(priv->mon,
>> +                                                  &new_iothreads)) < 0)
>> +        goto exit_monitor;
>> +
>> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
>> +        goto cleanup;
>> +
>> +    if (new_niothreads != exp_niothreads) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("got wrong number of IOThread ids from QEMU monitor. "
>> +                         "got %d, wanted %d"),
>> +                       new_niothreads, exp_niothreads);
>> +        vm->def->iothreads = new_niothreads;
>> +        goto cleanup;
>> +    }
>> +    vm->def->iothreads = exp_niothreads;
>> +
>> +    virDomainIOThreadIDDel(vm->def, iothread_id);
>> +
>> +    virDomainIOThreadSchedDelId(vm->def, iothread_id);
>> +
>> +    if (qemuDomainDelCgroupForThread(priv->cgroup,
>> +                                     VIR_CGROUP_THREAD_IOTHREAD,
>> +                                     iothread_id) < 0)
>> +        goto cleanup;
>> +
>> +    ret = 0;
>> +
>> + cleanup:
>> +    if (new_iothreads) {
>> +        for (idx = 0; idx < new_niothreads; idx++)
>> +            qemuMonitorIOThreadInfoFree(new_iothreads[idx]);
>> +        VIR_FREE(new_iothreads);
>> +    }
>> +    virDomainAuditIOThread(vm, orig_niothreads, new_niothreads,
>> +                           "update", rc == 0);
>> +    VIR_FREE(alias);
>> +    return ret;
>> +
>> + exit_monitor:
>> +    ignore_value(qemuDomainObjExitMonitor(driver, vm));
>> +    goto cleanup;
>> +}
>> +
>> +static int
>> +qemuDomainChgIOThread(virQEMUDriverPtr driver,
>> +                      virDomainObjPtr vm,
>> +                      unsigned int iothread_id,
>> +                      bool add,
>> +                      unsigned int flags)
>> +{
>> +    virQEMUDriverConfigPtr cfg = NULL;
>> +    virCapsPtr caps = NULL;
>> +    qemuDomainObjPrivatePtr priv;
>> +    virCgroupPtr cgroup_temp = NULL;
>> +    virBitmapPtr all_nodes = NULL;
>> +    char *all_nodes_str = NULL;
>> +    char *mem_mask = NULL;
> 
> It's nice that you've finally deleted the piece of code that has to deal
> with the DMA memory allocation issue with vCPU hotplug. You also could
> have deleted the corresponding variables that are now unused ... 
> 
>> +    virDomainDefPtr persistentDef;
>> +    int ret = -1;
>> +
>> +    cfg = virQEMUDriverGetConfig(driver);
>> +
>> +    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
>> +        goto cleanup;
>> +
>> +    priv = vm->privateData;
>> +
>> +    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
>> +        goto cleanup;
>> +
>> +    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
>> +                                        &persistentDef) < 0)
>> +        goto endjob;
>> +
>> +    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
>> +        if (!virDomainObjIsActive(vm)) {
>> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
>> +                           _("cannot change IOThreads for an inactive domain"));
>> +            goto endjob;
>> +        }
>> +
>> +        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_IOTHREAD)) {
>> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>> +                           _("IOThreads not supported with this binary"));
>> +            goto endjob;
>> +        }
>> +
>> +        if (add) {
>> +            if (qemuDomainHotplugAddIOThread(driver, vm, iothread_id) < 0)
>> +                goto endjob;
>> +        } else {
>> +            if (qemuDomainHotplugDelIOThread(driver, vm, iothread_id) < 0)
>> +                goto endjob;
>> +        }
>> +
>> +        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
>> +            goto endjob;
>> +    }
>> +
>> +    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
>> +        if (add) {
>> +            if (!virDomainIOThreadIDAdd(persistentDef, iothread_id))
>> +                goto endjob;
>> +
>> +            persistentDef->iothreads++;
>> +        } else {
>> +            virDomainIOThreadIDDefPtr iothrid;
>> +            if (!(iothrid = virDomainIOThreadIDFind(persistentDef,
>> +                                                    iothread_id))) {
>> +                virReportError(VIR_ERR_INVALID_ARG,
>> +                               _("cannot find IOThread '%u' in persistent "
>> +                                 "iothreadids"),
>> +                               iothread_id);
>> +                goto cleanup;
>> +            }
>> +
>> +            virDomainIOThreadIDDel(persistentDef, iothread_id);
>> +            virDomainIOThreadSchedDelId(persistentDef, iothread_id);
>> +            persistentDef->iothreads--;
>> +        }
>> +
>> +        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
>> +            goto endjob;
>> +    }
>> +
>> +    ret = 0;
>> +
>> + endjob:
>> +    if (mem_mask) {
>> +        virErrorPtr err = virSaveLastError();
>> +        virCgroupSetCpusetMems(cgroup_temp, mem_mask);
>> +        virSetError(err);
>> +        virFreeError(err);
>> +    }
>> +    qemuDomainObjEndJob(driver, vm);
>> +
>> + cleanup:
>> +    VIR_FREE(mem_mask);
>> +    VIR_FREE(all_nodes_str);
>> +    virBitmapFree(all_nodes);
>> +    virCgroupFree(&cgroup_temp);
>> +    virObjectUnref(caps);
>> +    virObjectUnref(cfg);
>> +    return ret;
>> +}
> 
> ACK if you clean up qemuDomainChgIOThread()
> 

done... with the following squashed in.

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e1a6265..443341b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6452,10 +6452,6 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver,
     virQEMUDriverConfigPtr cfg = NULL;
     virCapsPtr caps = NULL;
     qemuDomainObjPrivatePtr priv;
-    virCgroupPtr cgroup_temp = NULL;
-    virBitmapPtr all_nodes = NULL;
-    char *all_nodes_str = NULL;
-    char *mem_mask = NULL;
     virDomainDefPtr persistentDef;
     int ret = -1;
 
@@ -6527,19 +6523,9 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver,
     ret = 0;
 
  endjob:
-    if (mem_mask) {
-        virErrorPtr err = virSaveLastError();
-        virCgroupSetCpusetMems(cgroup_temp, mem_mask);
-        virSetError(err);
-        virFreeError(err);
-    }
     qemuDomainObjEndJob(driver, vm);
 
  cleanup:
-    VIR_FREE(mem_mask);
-    VIR_FREE(all_nodes_str);
-    virBitmapFree(all_nodes);
-    virCgroupFree(&cgroup_temp);
     virObjectUnref(caps);
     virObjectUnref(cfg);
     return ret;





More information about the libvir-list mailing list