]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
API/qemu: add async unplug flag to virDomainSetVcpusFlags
authorAkash Kulhalli via Devel <devel@lists.libvirt.org>
Wed, 29 Apr 2026 12:13:28 +0000 (17:43 +0530)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 12 May 2026 11:39:07 +0000 (13:39 +0200)
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 the async path in the setvcpus subcommand.

Signed-off-by: Akash Kulhalli <akash.kulhalli@oracle.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
docs/manpages/virsh.rst
include/libvirt/libvirt-domain.h
src/libvirt-domain.c
src/qemu/qemu_driver.c
tools/virsh-domain.c

index 80b0ea14a8b3df9c379982163f0b83e629d4d5eb..cbec83daa8b526e2a8dcc1351709190c9c8629fc 100644 (file)
@@ -4810,7 +4810,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 +4839,11 @@ 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. Final completion is reported by the ``vcpu-removed``
+domain event, while rejected unplug requests continue to be reported by
+``device-removal-failed``. 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.
index 21336df85bd8ff2850f91a56874cf2097a904761..8902742a5ec8bd11dd2acb5fff04d0707380e2bc 100644 (file)
@@ -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.4.0) */
 } virDomainVcpuFlags;
 
 int                     virDomainSetVcpus       (virDomainPtr domain,
index db9eea57745c4cb797599622fcdc70ab40d44919..97af1099f939fd1be6776563be16834c55e74833 100644 (file)
@@ -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.
index ae4d8982ee81f6a67c1f14bf421b3c0ce92505df..40fd7af3116430000a9cb82ee28ccfbde2d5e611 100644 (file)
@@ -4267,6 +4267,7 @@ qemuDomainSetVcpusFlags(virDomainPtr dom,
     virDomainObj *vm = NULL;
     virDomainDef *def;
     virDomainDef *persistentDef;
+    bool async_unplug = !!(flags & VIR_DOMAIN_VCPU_ASYNC_UNPLUG);
     bool hotpluggable = !!(flags & VIR_DOMAIN_VCPU_HOTPLUGGABLE);
     bool useAgent = !!(flags & VIR_DOMAIN_VCPU_GUEST);
     int ret = -1;
@@ -4275,7 +4276,8 @@ qemuDomainSetVcpusFlags(virDomainPtr dom,
                   VIR_DOMAIN_AFFECT_CONFIG |
                   VIR_DOMAIN_VCPU_MAXIMUM |
                   VIR_DOMAIN_VCPU_GUEST |
-                  VIR_DOMAIN_VCPU_HOTPLUGGABLE, -1);
+                  VIR_DOMAIN_VCPU_HOTPLUGGABLE |
+                  VIR_DOMAIN_VCPU_ASYNC_UNPLUG, -1);
 
     if (!(vm = qemuDomainObjFromDomain(dom)))
         goto cleanup;
@@ -4295,13 +4297,19 @@ qemuDomainSetVcpusFlags(virDomainPtr dom,
     if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
         goto endjob;
 
+    if (async_unplug && useAgent) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("asynchronous mode is unsupported with VIR_DOMAIN_VCPU_GUEST"));
+        goto endjob;
+    }
+
     if (useAgent)
         ret = qemuDomainSetVcpusAgent(vm, nvcpus);
     else if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
         ret = qemuDomainSetVcpusMax(driver, vm, def, persistentDef, nvcpus);
     else
         ret = qemuDomainSetVcpusInternal(driver, vm, def, persistentDef,
-                                         nvcpus, hotpluggable, false);
+                                         nvcpus, hotpluggable, async_unplug);
 
  endjob:
     if (useAgent)
index 08a1ce3953783bf3a327caf2db6c2ba91377ad45..1fccee4bc9ed25ca222584a584f264772f43c7e6 100644 (file)
@@ -7667,6 +7667,10 @@ static const vshCmdOptDef opts_setvcpus[] = {
      .type = VSH_OT_BOOL,
      .help = N_("make added vcpus hot(un)pluggable")
     },
+    {.name = "async",
+     .type = VSH_OT_BOOL,
+     .help = N_("return after firing vcpu unplug request(s)")
+    },
     {.name = NULL}
 };
 
@@ -7681,11 +7685,13 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
     bool current = vshCommandOptBool(cmd, "current");
     bool guest = vshCommandOptBool(cmd, "guest");
     bool hotpluggable = vshCommandOptBool(cmd, "hotpluggable");
+    bool async = vshCommandOptBool(cmd, "async");
     unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
 
     VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
     VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
     VSH_EXCLUSIVE_OPTIONS_VAR(guest, config);
+    VSH_EXCLUSIVE_OPTIONS_VAR(async, guest);
 
     VSH_REQUIRE_OPTION_VAR(maximum, config);
 
@@ -7699,6 +7705,8 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
         flags |= VIR_DOMAIN_VCPU_MAXIMUM;
     if (hotpluggable)
         flags |= VIR_DOMAIN_VCPU_HOTPLUGGABLE;
+    if (async)
+        flags |= VIR_DOMAIN_VCPU_ASYNC_UNPLUG;
 
     if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
         return false;