On Thu, Apr 23, 2026 at 17:27:29 +0530, Akash Kulhalli via Devel wrote:
> Add VIR_DOMAIN_SETVCPU_ASYNC_UNPLUG for virDomainSetVcpu().
>
> Define a dedicated virDomainSetVcpuBehaviour flag type and wire the
> new flag through the QEMU driver. As with setvcpus async unplug,
> success indicates request acceptance while final completion is
> reported by the vcpu-removed event.
>
> Update the API documentation and add virsh support for setvcpu
> --async.
>
> Signed-off-by: Akash Kulhalli <[email protected]>
> ---
> docs/manpages/virsh.rst | 10 ++++++++--
> include/libvirt/libvirt-domain.h | 14 ++++++++++++++
> src/libvirt-domain.c | 11 ++++++++++-
> src/qemu/qemu_driver.c | 12 ++++++++++--
> tools/virsh-domain.c | 8 ++++++++
> 5 files changed, 50 insertions(+), 5 deletions(-)
>
> diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
> index f4c8e573cd47..7b3c853aea27 100644
> --- a/docs/manpages/virsh.rst
> +++ b/docs/manpages/virsh.rst
> @@ -180,7 +180,7 @@ setvcpus and setmem. In those cases the fact that the
> ``virsh``
> program returned, may not mean the action is complete and you
> must poll periodically to detect that the guest completed the
> operation. This asynchronous behaviour can be enforced with the
> -``--async`` flag to ``setvcpus`` only.
> +``--async`` flag to ``setvcpus`` and ``setvcpu`` only.
See 4/5
>
> ``virsh`` strives for backward compatibility. Although the ``help``
> command only lists the preferred usage of a command, if an older
[...]
> @@ -4891,6 +4891,12 @@ If *--current* is specified, it is equivalent to
> either *--live* or
> default. Both *--live* and *--config* flags may be given, but
> *--current* is exclusive.
>
> +If *--async* is specified with *--disable*, live vCPU unplug requests are
> +fired without waiting for the guest to comply. This may optionally be
> +combined with *--config*. Final completion of this operation is reported
> +by the ``vcpu-removed`` domain event, while rejected unplug requests continue
> +to be reported by ``device-removal-failed``.
Apply relevant comments from 4/5
> +
>
> shutdown
> --------
> diff --git a/include/libvirt/libvirt-domain.h
> b/include/libvirt/libvirt-domain.h
> index 016b6ea700e9..2b6c498ed5ab 100644
> --- a/include/libvirt/libvirt-domain.h
> +++ b/include/libvirt/libvirt-domain.h
> @@ -329,6 +329,20 @@ typedef enum {
> /* 1 << 2 is reserved for virTypedParameterFlags */
> } virDomainModificationImpact;
>
> +/**
> + * virDomainSetVcpuBehaviour:
> + *
> + * These flags must be used when calling the `virDomainSetVcpu` API.
> + *
> + * Since: 12.3.0
12.4.0
> + */
> +typedef enum {
> + VIR_DOMAIN_SETVCPU_AFFECT_CURRENT = VIR_DOMAIN_AFFECT_CURRENT, /* Affect
> current domain state. (Since: 0.9.2) */
The 'Since' tag applies to the name of the flag in the docs. The flag
didn't exist since 0.9.2, but only after 12.4.0.
You can use the prefix style (move the comment above the flag name,
which allows more text) and mention that it's an alias of
VIR_DOMAIN_AFFECT_CURRENT, then use the
proper version
> + VIR_DOMAIN_SETVCPU_AFFECT_LIVE = VIR_DOMAIN_AFFECT_LIVE, /* Affect
> running domain state. (Since: 0.9.2) */
> + VIR_DOMAIN_SETVCPU_AFFECT_CONFIG = VIR_DOMAIN_AFFECT_CONFIG, /* Affect
> persistent domain state. (Since: 0.9.2) */
ditto
> + VIR_DOMAIN_SETVCPU_ASYNC_UNPLUG = 1 << 2 /* Do not wait for the guest to
> comply with the request (Since: 12.3.0) */
12.4.0
> +} virDomainSetVcpuBehaviour;
Naming scheme for these is virDomainSetVcpuFlags.
> +
> /**
> * virDomainInfo:
> *
> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
> index 97af1099f939..e3d1b76bcd01 100644
> --- a/src/libvirt-domain.c
> +++ b/src/libvirt-domain.c
> @@ -13135,7 +13135,7 @@ virDomainSetGuestVcpus(virDomainPtr domain,
> * @domain: pointer to domain object
> * @vcpumap: text representation of a bitmap of vcpus to set
> * @state: 0 to disable/1 to enable cpus described by @vcpumap
> - * @flags: bitwise-OR of virDomainModificationImpact
> + * @flags: bitwise-OR of virDomainSetVcpuBehaviour
Don't forget to fix name here after you fix the enum name.
> *
> * Enables/disables individual vcpus described by @vcpumap in the hypervisor.
> *
> @@ -13144,6 +13144,15 @@ virDomainSetGuestVcpus(virDomainPtr domain,
> *
> * Note that OSes and hypervisors may require vCPU 0 to stay online.
> *
> + * If @flags includes VIR_DOMAIN_SETVCPU_ASYNC_UNPLUG, live vCPU disable
> (hot-unplug)
> + * request(s) are fired without waiting for the guest to comply. Success in
> + * this mode means only that the unplug request(s) were accepted. Final
> + * completion is reported by VIR_DOMAIN_EVENT_ID_VCPU_REMOVED, carrying the
> + * XML ``<vcpu id='...'>`` value for each removed vCPU. Rejected unplug
> + * requests continue to be reported by
> VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED.
> + * The success event may be delivered before this API call returns. This flag
> + * has no effect when the selected vCPUs are enabled.
> + *
> * Returns 0 on success, -1 on error.
> *
> * Since: 3.1.0
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index c9c72b29617f..9a20486725cb 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -19177,12 +19177,14 @@ qemuDomainSetVcpu(virDomainPtr dom,
> virDomainObj *vm = NULL;
> virDomainDef *def = NULL;
> virDomainDef *persistentDef = NULL;
> + bool async_unplug = !!(flags & VIR_DOMAIN_SETVCPU_ASYNC_UNPLUG);
> g_autoptr(virBitmap) map = NULL;
> ssize_t lastvcpu;
> int ret = -1;
>
> virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
> - VIR_DOMAIN_AFFECT_CONFIG, -1);
> + VIR_DOMAIN_AFFECT_CONFIG |
> + VIR_DOMAIN_SETVCPU_ASYNC_UNPLUG, -1);
>
> if (state != 0 && state != 1) {
> virReportInvalidArg(state, "%s", _("unsupported state value"));
> @@ -19228,8 +19230,14 @@ qemuDomainSetVcpu(virDomainPtr dom,
> }
> }
>
> + if (async_unplug && (!def)) {
> + virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> + _("asynchronous mode is supported only for live vcpu
> unplug"));
> + goto endjob;
> + }
Drop this.
> +
> ret = qemuDomainSetVcpuInternal(driver, vm, def, persistentDef, map,
> - !!state, false);
> + !!state, async_unplug);
>
> endjob:
> virDomainObjEndJob(vm);