On Thu, Apr 23, 2026 at 17:27:28 +0530, Akash Kulhalli via Devel wrote:
> Add VIR_DOMAIN_VCPU_ASYNC_UNPLUG for virDomainSetVcpusFlags().
>
> With this flag, success indicates that QEMU accepted the unplug
> request, while final completion is reported by the vcpu-removed
> event. Rejected requests continue to be reported by the
> device-removal-failed event.
>
> Wire the flag through the QEMU driver, document its semantics, and
> add virsh support for setvcpus --async.
>
> Signed-off-by: Akash Kulhalli <[email protected]>
> ---
> docs/manpages/virsh.rst | 13 +++++++++++--
> include/libvirt/libvirt-domain.h | 1 +
> src/libvirt-domain.c | 10 ++++++++++
> src/qemu/qemu_driver.c | 12 ++++++++++--
> tools/virsh-domain.c | 8 ++++++++
> 5 files changed, 40 insertions(+), 4 deletions(-)
>
> diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
> index 80b0ea14a8b3..f4c8e573cd47 100644
> --- a/docs/manpages/virsh.rst
> +++ b/docs/manpages/virsh.rst
> @@ -179,7 +179,8 @@ Most ``virsh`` commands act synchronously, except maybe
> shutdown,
> 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.
> +operation. This asynchronous behaviour can be enforced with the
> +``--async`` flag to ``setvcpus`` only.
Skip this part. The command is synchronous and the async mode is
explicitly documented with the command.
>
> ``virsh`` strives for backward compatibility. Although the ``help``
> command only lists the preferred usage of a command, if an older
> @@ -4810,7 +4811,7 @@ setvcpus
>
> ::
>
> - setvcpus domain count [--maximum] [[--config] [--live] | [--current]]
> [--guest] [--hotpluggable]
> + setvcpus domain count [--maximum] [[--config] [--live] | [--current]]
> [--guest] [--hotpluggable] [--async]
>
> Change the number of virtual CPUs active in a guest domain. By default,
> this command works on active guest domains. To change the settings for an
> @@ -4839,6 +4840,14 @@ is up to the hypervisor whether the *--config* flag is
> also assumed, and
> therefore whether the XML configuration is adjusted to make the change
> persistent.
>
> +If *--async* is specified, live vCPU unplug requests are fired without
> waiting
> +for the guest to comply. This affects only the live unplug part of the
> +operation; it may optionally be combined with *--config*. Final completion is
Drop the 'This affects only the...' sentence. The previous one documents
it sufficiently.
> +reported by the ``vcpu-removed`` domain event, while rejected unplug requests
> +continue to be reported by ``device-removal-failed``. If the requested count
> +increases the live vCPU count, or only affects the persistent configuration,
This sentence is also redundant IMO.
> +*--async* has no effect. This flag cannot be combined with *--guest*.
> +
> If *--guest* is specified, then the count of cpus is modified in the guest
> instead of the hypervisor. This flag is usable only for live domains
> and may require guest agent to be configured in the guest.
> diff --git a/include/libvirt/libvirt-domain.h
> b/include/libvirt/libvirt-domain.h
> index 92d5ecb32d65..016b6ea700e9 100644
> --- a/include/libvirt/libvirt-domain.h
> +++ b/include/libvirt/libvirt-domain.h
> @@ -2605,6 +2605,7 @@ typedef enum {
> VIR_DOMAIN_VCPU_MAXIMUM = (1 << 2), /* Max rather than current count
> (Since: 0.8.5) */
> VIR_DOMAIN_VCPU_GUEST = (1 << 3), /* Modify state of the cpu in the
> guest (Since: 1.1.0) */
> VIR_DOMAIN_VCPU_HOTPLUGGABLE = (1 << 4), /* Make vcpus added
> hot(un)pluggable (Since: 2.4.0) */
> + VIR_DOMAIN_VCPU_ASYNC_UNPLUG = (1 << 5), /* Don't wait for the guest to
> comply with unplug request(s) (Since: 12.3.0) */
12.4.0
> } virDomainVcpuFlags;
>
> int virDomainSetVcpus (virDomainPtr domain,
> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
> index db9eea57745c..97af1099f939 100644
> --- a/src/libvirt-domain.c
> +++ b/src/libvirt-domain.c
> @@ -7773,6 +7773,16 @@ virDomainSetVcpus(virDomainPtr domain, unsigned int
> nvcpus)
> * be used with live guests and is incompatible with VIR_DOMAIN_VCPU_MAXIMUM.
> * The usage of this flag may require a guest agent configured.
> *
> + * If @flags includes VIR_DOMAIN_VCPU_ASYNC_UNPLUG, live vCPU hot-unplug
> + * request(s) are fired without waiting for the guest to comply. Success in
> + * this mode only means 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 through the event
> + * VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED. The success event may be
> + * delivered before this API call returns. This flag has no effect when this
> + * operation results in an increase in the live vCPU count.
> + *
> * Not all hypervisors can support all flag combinations.
> *
> * Returns 0 in case of success, -1 in case of failure.
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 4d9be3d3a9e5..c9c72b29617f 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
[...]
> @@ -4297,13 +4299,19 @@ qemuDomainSetVcpusFlags(virDomainPtr dom,
> if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
> goto endjob;
>
> + if (async_unplug && (useAgent || !def)) {
> + virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> + _("asynchronous mode is supported only for live vcpu
> unplug"));
Technically the unplug with guest agent (e.g. the --guest mode) is still
live so this error message is a bit misleading.
Drop the '!def' part of the condition since it IMO makes no sense and
mention the flag name (VIR_DOMAIN_VCPU_GUEST).
With the above:
Reviewed-by: Peter Krempa <[email protected]>