Thread an async_unplug flag through the internal QEMU vCPU unplug helpers. When set, the unplug path returns after QEMU accepts the device deletion request and leaves final completion to the existing DEVICE_DELETED handling routines. All callers still pass false, so this does not change behaviour yet. Signed-off-by: Akash Kulhalli <akash.kulhalli@oracle.com> --- src/qemu/qemu_driver.c | 5 ++-- src/qemu/qemu_hotplug.c | 52 +++++++++++++++++++++++++++++++++-------- src/qemu/qemu_hotplug.h | 6 +++-- tests/qemuhotplugtest.c | 5 ++-- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d227ac58cdb4..4d9be3d3a9e5 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4303,7 +4303,7 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, ret = qemuDomainSetVcpusMax(driver, vm, def, persistentDef, nvcpus); else ret = qemuDomainSetVcpusInternal(driver, vm, def, persistentDef, - nvcpus, hotpluggable); + nvcpus, hotpluggable, false); endjob: if (useAgent) @@ -19220,7 +19220,8 @@ qemuDomainSetVcpu(virDomainPtr dom, } } - ret = qemuDomainSetVcpuInternal(driver, vm, def, persistentDef, map, !!state); + ret = qemuDomainSetVcpuInternal(driver, vm, def, persistentDef, map, + !!state, false); endjob: virDomainObjEndJob(vm); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 7828b7d73821..919224ed69f7 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -6793,7 +6793,8 @@ static int qemuDomainHotplugDelVcpu(virQEMUDriver *driver, virQEMUDriverConfig *cfg, virDomainObj *vm, - unsigned int vcpu) + unsigned int vcpu, + bool async_unplug) { virDomainVcpuDef *vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu); qemuDomainVcpuPrivate *vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); @@ -6808,7 +6809,8 @@ qemuDomainHotplugDelVcpu(virQEMUDriver *driver, return -1; } - qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias); + if (!async_unplug) + qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias); rc = qemuDomainDeleteDevice(vm, vcpupriv->alias); if (rc < 0) { @@ -6817,6 +6819,12 @@ qemuDomainHotplugDelVcpu(virQEMUDriver *driver, virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false); goto cleanup; } + } else if (async_unplug) { + /* + * Let DEVICE_DELETED finish the unplug asynchronously when qemu + * accepted the delete request. + */ + return 0; } else { if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) { if (rc == 0) @@ -6837,7 +6845,8 @@ qemuDomainHotplugDelVcpu(virQEMUDriver *driver, ret = 0; cleanup: - qemuDomainResetDeviceRemoval(vm); + if (!async_unplug) + qemuDomainResetDeviceRemoval(vm); return ret; } @@ -7008,7 +7017,8 @@ qemuDomainSetVcpusLive(virQEMUDriver *driver, virQEMUDriverConfig *cfg, virDomainObj *vm, virBitmap *vcpumap, - bool enable) + bool enable, + bool async) { qemuDomainObjPrivate *priv = vm->privateData; virCgroupEmulatorAllNodesData *emulatorCgroup = NULL; @@ -7028,7 +7038,7 @@ qemuDomainSetVcpusLive(virQEMUDriver *driver, if (!virBitmapIsBitSet(vcpumap, nextvcpu)) continue; - if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu) < 0) + if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu, async) < 0) goto cleanup; } } @@ -7119,7 +7129,8 @@ qemuDomainSetVcpusInternal(virQEMUDriver *driver, virDomainDef *def, virDomainDef *persistentDef, unsigned int nvcpus, - bool hotpluggable) + bool hotpluggable, + bool async_unplug) { g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); g_autoptr(virBitmap) vcpumap = NULL; @@ -7144,7 +7155,8 @@ qemuDomainSetVcpusInternal(virQEMUDriver *driver, &enable))) return -1; - if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) + if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable, + async_unplug) < 0) return -1; } @@ -7287,14 +7299,33 @@ qemuDomainVcpuValidateConfig(virDomainDef *def, return 0; } - +/** + * qemuDomainSetVcpuInternal: + * + * When @async_unplug is set to true, libvirt will not wait for + * the guest to comply with the unplug request but instead return + * immediately after receiving the acknowledgement from QEMU. Otherwise, + * libvirt will wait for a brief moment (defined by qemuDomainGetUnplugTimeout) + * before giving up and returning control to the caller. + * + * If the request results in adding a vcpu, this parameter is ignored. + * + * @param driver the QEMU driver object + * @param vm the domain object + * @param def the live domain definition + * @param persistentDef the persistent (config) domain definition + * @param map a bitmap of cpus to be set to state @state + * @param state enable/disable the vcpus marked in @map + * @param async_unplug only used in case of unplug (i.e. @state=false) + */ int qemuDomainSetVcpuInternal(virQEMUDriver *driver, virDomainObj *vm, virDomainDef *def, virDomainDef *persistentDef, virBitmap *map, - bool state) + bool state, + bool async_unplug) { g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); g_autoptr(virBitmap) livevcpus = NULL; @@ -7326,7 +7357,8 @@ qemuDomainSetVcpuInternal(virQEMUDriver *driver, } if (livevcpus && - qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0) + qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state, + async_unplug) < 0) return -1; if (persistentDef) { diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index e6c90253e416..60ed0e174c21 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -106,7 +106,8 @@ qemuDomainSetVcpusInternal(virQEMUDriver *driver, virDomainDef *def, virDomainDef *persistentDef, unsigned int nvcpus, - bool hotpluggable); + bool hotpluggable, + bool async_unplug); int qemuDomainSetVcpuInternal(virQEMUDriver *driver, @@ -114,7 +115,8 @@ qemuDomainSetVcpuInternal(virQEMUDriver *driver, virDomainDef *def, virDomainDef *persistentDef, virBitmap *vcpus, - bool state); + bool state, + bool async_unplug); unsigned long long qemuDomainGetUnplugTimeout(virDomainObj *vm) ATTRIBUTE_MOCKABLE; diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index ea9d3243f8b1..7e49b9ad3661 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -420,7 +420,7 @@ testQemuHotplugCpuGroup(const void *opaque) rc = qemuDomainSetVcpusInternal(&driver, data->vm, data->vm->def, data->vm->newDef, params->newcpus, - true); + true, false); if (params->fail) { if (rc == 0) @@ -458,7 +458,8 @@ testQemuHotplugCpuIndividual(const void *opaque) goto cleanup; rc = qemuDomainSetVcpuInternal(&driver, data->vm, data->vm->def, - data->vm->newDef, map, params->state); + data->vm->newDef, map, params->state, + false); if (params->fail) { if (rc == 0) -- 2.47.3