Blame SOURCES/libvirt-qemu_hotplug-consolidate-all-common-detach-code-in-qemuDomainDetachDeviceLive.patch

0a7476
From d16f6dc87b5122c6d14ffb52a7276aef8f14049c Mon Sep 17 00:00:00 2001
0a7476
Message-Id: <d16f6dc87b5122c6d14ffb52a7276aef8f14049c@dist-git>
0a7476
From: Laine Stump <laine@laine.org>
0a7476
Date: Thu, 11 Apr 2019 15:14:51 -0400
0a7476
Subject: [PATCH] qemu_hotplug: consolidate all common detach code in
0a7476
 qemuDomainDetachDeviceLive
0a7476
0a7476
Now that all the qemuDomainDetachPrep*() functions look nearly
0a7476
identical at the end, we can put one copy of that identical code in
0a7476
qemuDomainDetachDeviceLive() at the point after the individual prep
0a7476
functions have been called, and remove the duplicated code from all
0a7476
the prep functions. The code to locate the target "detach" device
0a7476
based on the "match" device remains, as do all device-type-specific
0a7476
validations.
0a7476
0a7476
Unfortunately there are a few things going on at once in this patch,
0a7476
which makes it a bit more difficult to follow than the others; it was
0a7476
just impossible to do the changes in stages and still have a
0a7476
buildable/testable tree at each step.
0a7476
0a7476
The other changes of note:
0a7476
0a7476
* The individual prep functions no longer need their driver or async
0a7476
  args, so those are removed, as are the local "ret" variables, since
0a7476
  in all cases the functions just directly return -1 or 0.
0a7476
0a7476
* Some of the prep functions were checking for a valid alias and/or
0a7476
  for attempts to detach a multifunction PCI device, but not all. In
0a7476
  fact, both checks are valid (or at least harmless) for *all* device
0a7476
  types, so they are removed from the prep functions, and done a
0a7476
  single time in the common function.
0a7476
0a7476
  (any attempts to *create* an alias when there isn't one has been
0a7476
  removed, since that is doomed to failure anyway; the only way the
0a7476
  device wouldn't have an alias is if 1) the domain was created by
0a7476
  calling virsh qemu-attach to attach an existing qemu process to
0a7476
  libvirt, and 2) the qemu command that started said process used "old
0a7476
  style" arguments for creating devices that didn't have any device
0a7476
  ids. Even if we constructed a device id for one of these devices,
0a7476
  qemu wouldn't recognize it in the device_del command anyway, so we
0a7476
  may as well fail earlier with "device missing alias" rather than
0a7476
  failing later with "couldn't delete device net0".)
0a7476
0a7476
* Only one type of device has shutdown code that must not be called
0a7476
  until after *all* validation of the device is done (including
0a7476
  checking for multifunction PCI and valid alias, which is done in the
0a7476
  toplevel common code). For this reason, the Net function has been
0a7476
  split in two, with the 2nd half (qemuDomainDetachShutdownNet())
0a7476
  called from the common function, right before sending the delete
0a7476
  command to qemu.
0a7476
0a7476
Signed-off-by: Laine Stump <laine@laine.org>
0a7476
ACKed-by: Peter Krempa <pkrempa@redhat.com>
0a7476
(cherry picked from commit dd60bd62d3ad60b564168f56b05f4c9354af4bd3)
0a7476
0a7476
Partially-Resolves: https://bugzilla.redhat.com/1658198
0a7476
Signed-off-by: Laine Stump <laine@redhat.com>
0a7476
Signed-off-by: Laine Stump <laine@laine.org>
0a7476
Message-Id: <20190411191453.24055-40-laine@redhat.com>
0a7476
Acked-by: Michal Privoznik <mprivozn@redhat.com>
0a7476
---
0a7476
 src/qemu/qemu_hotplug.c | 480 ++++++++++++----------------------------
0a7476
 1 file changed, 142 insertions(+), 338 deletions(-)
0a7476
0a7476
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
0a7476
index 390fc36cf6..27d09d173b 100644
0a7476
--- a/src/qemu/qemu_hotplug.c
0a7476
+++ b/src/qemu/qemu_hotplug.c
0a7476
@@ -4650,7 +4650,7 @@ qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
0a7476
 }
0a7476
 
0a7476
 
0a7476
-static void ATTRIBUTE_UNUSED
0a7476
+static void
0a7476
 qemuDomainRemoveAuditDevice(virDomainObjPtr vm,
0a7476
                             virDomainDeviceDefPtr detach,
0a7476
                             bool success)
0a7476
@@ -4902,15 +4902,12 @@ qemuFindDisk(virDomainDefPtr def, const char *dst)
0a7476
 }
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepDisk(virQEMUDriverPtr driver,
0a7476
-                         virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepDisk(virDomainObjPtr vm,
0a7476
                          virDomainDiskDefPtr match,
0a7476
-                         virDomainDiskDefPtr *detach,
0a7476
-                         bool async)
0a7476
+                         virDomainDiskDefPtr *detach)
0a7476
 {
0a7476
     virDomainDiskDefPtr disk;
0a7476
     int idx;
0a7476
-    int ret = -1;
0a7476
 
0a7476
     if ((idx = qemuFindDisk(vm->def, match->dst)) < 0) {
0a7476
         virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
@@ -4962,34 +4959,7 @@ qemuDomainDetachPrepDisk(virQEMUDriverPtr driver,
0a7476
     if (qemuDomainDiskBlockJobIsActive(disk))
0a7476
         return -1;
0a7476
 
0a7476
-    if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO &&
0a7476
-        qemuIsMultiFunctionDevice(vm->def, &disk->info)) {
0a7476
-        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
-                       _("cannot hot unplug multifunction PCI device: %s"),
0a7476
-                       disk->dst);
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &disk->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, disk->info.alias) < 0) {
0a7476
-        if (virDomainObjIsActive(vm))
0a7476
-            virDomainAuditDisk(vm, disk->src, NULL, "detach", false);
0a7476
-        goto cleanup;
0a7476
-    }
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveDiskDevice(driver, vm, disk);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
@@ -5054,13 +5024,11 @@ static bool qemuDomainControllerIsBusy(virDomainObjPtr vm,
0a7476
 }
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepController(virQEMUDriverPtr driver,
0a7476
-                               virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepController(virDomainObjPtr vm,
0a7476
                                virDomainControllerDefPtr match,
0a7476
-                               virDomainControllerDefPtr *detach,
0a7476
-                               bool async)
0a7476
+                               virDomainControllerDefPtr *detach)
0a7476
 {
0a7476
-    int idx, ret = -1;
0a7476
+    int idx;
0a7476
     virDomainControllerDefPtr controller = NULL;
0a7476
 
0a7476
     if (match->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
0a7476
@@ -5075,50 +5043,26 @@ qemuDomainDetachPrepController(virQEMUDriverPtr driver,
0a7476
                        _("controller %s:%d not found"),
0a7476
                        virDomainControllerTypeToString(match->type),
0a7476
                        match->idx);
0a7476
-        goto cleanup;
0a7476
+        return -1;
0a7476
     }
0a7476
 
0a7476
     *detach = controller = vm->def->controllers[idx];
0a7476
 
0a7476
-    if (qemuIsMultiFunctionDevice(vm->def, &controller->info)) {
0a7476
-        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
-                       "%s", _("cannot hot unplug multifunction PCI device"));
0a7476
-        goto cleanup;
0a7476
-    }
0a7476
-
0a7476
     if (qemuDomainControllerIsBusy(vm, controller)) {
0a7476
         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
0a7476
                        _("device cannot be detached: device is busy"));
0a7476
-        goto cleanup;
0a7476
+        return -1;
0a7476
     }
0a7476
 
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &controller->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, controller->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveControllerDevice(driver, vm, controller);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 /* search for a hostdev matching dev and detach it */
0a7476
 static int
0a7476
-qemuDomainDetachPrepHostdev(virQEMUDriverPtr driver,
0a7476
-                            virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepHostdev(virDomainObjPtr vm,
0a7476
                             virDomainHostdevDefPtr match,
0a7476
-                            virDomainHostdevDefPtr *detach,
0a7476
-                            bool async)
0a7476
+                            virDomainHostdevDefPtr *detach)
0a7476
 {
0a7476
     virDomainHostdevSubsysPtr subsys = &match->source.subsys;
0a7476
     virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
0a7476
@@ -5127,7 +5071,6 @@ qemuDomainDetachPrepHostdev(virQEMUDriverPtr driver,
0a7476
     virDomainHostdevSubsysMediatedDevPtr mdevsrc = &subsys->u.mdev;
0a7476
     virDomainHostdevDefPtr hostdev = NULL;
0a7476
     int idx;
0a7476
-    int ret = -1;
0a7476
 
0a7476
     if (match->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
0a7476
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
0a7476
@@ -5190,54 +5133,15 @@ qemuDomainDetachPrepHostdev(virQEMUDriverPtr driver,
0a7476
         return -1;
0a7476
     }
0a7476
 
0a7476
-    if (qemuIsMultiFunctionDevice(vm->def, hostdev->info)) {
0a7476
-        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
-                       _("cannot hot unplug multifunction PCI device with guest address: "
0a7476
-                         "%.4x:%.2x:%.2x.%.1x"),
0a7476
-                       hostdev->info->addr.pci.domain, hostdev->info->addr.pci.bus,
0a7476
-                       hostdev->info->addr.pci.slot, hostdev->info->addr.pci.function);
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!hostdev->info->alias) {
0a7476
-        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
-                       "%s", _("device cannot be detached without a device alias"));
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, hostdev->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, hostdev->info->alias) < 0) {
0a7476
-        if (virDomainObjIsActive(vm))
0a7476
-            virDomainAuditHostdev(vm, hostdev, "detach", false);
0a7476
-        goto cleanup;
0a7476
-    }
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveHostDevice(driver, vm, hostdev);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-
0a7476
-    return ret;
0a7476
-
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepShmem(virQEMUDriverPtr driver,
0a7476
-                          virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepShmem(virDomainObjPtr vm,
0a7476
                           virDomainShmemDefPtr match,
0a7476
-                          virDomainShmemDefPtr *detach,
0a7476
-                          bool async)
0a7476
+                          virDomainShmemDefPtr *detach)
0a7476
 {
0a7476
-    int ret = -1;
0a7476
     ssize_t idx = -1;
0a7476
     virDomainShmemDefPtr shmem = NULL;
0a7476
 
0a7476
@@ -5265,34 +5169,15 @@ qemuDomainDetachPrepShmem(virQEMUDriverPtr driver,
0a7476
         return -1;
0a7476
     }
0a7476
 
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &shmem->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, shmem->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveShmemDevice(driver, vm, shmem);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepWatchdog(virQEMUDriverPtr driver,
0a7476
-                             virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepWatchdog(virDomainObjPtr vm,
0a7476
                              virDomainWatchdogDefPtr match,
0a7476
-                             virDomainWatchdogDefPtr *detach,
0a7476
-                             bool async)
0a7476
+                             virDomainWatchdogDefPtr *detach)
0a7476
 {
0a7476
-    int ret = -1;
0a7476
     virDomainWatchdogDefPtr watchdog;
0a7476
 
0a7476
     *detach = watchdog = vm->def->watchdog;
0a7476
@@ -5323,34 +5208,15 @@ qemuDomainDetachPrepWatchdog(virQEMUDriverPtr driver,
0a7476
         return -1;
0a7476
     }
0a7476
 
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &watchdog->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, watchdog->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveWatchdog(driver, vm, watchdog);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepRedirdev(virQEMUDriverPtr driver,
0a7476
-                             virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepRedirdev(virDomainObjPtr vm,
0a7476
                              virDomainRedirdevDefPtr match,
0a7476
-                             virDomainRedirdevDefPtr *detach,
0a7476
-                             bool async)
0a7476
+                             virDomainRedirdevDefPtr *detach)
0a7476
 {
0a7476
-    int ret = -1;
0a7476
     virDomainRedirdevDefPtr redirdev;
0a7476
     ssize_t idx;
0a7476
 
0a7476
@@ -5362,59 +5228,41 @@ qemuDomainDetachPrepRedirdev(virQEMUDriverPtr driver,
0a7476
 
0a7476
     *detach = redirdev = vm->def->redirdevs[idx];
0a7476
 
0a7476
-    if (!redirdev->info.alias) {
0a7476
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
0a7476
-                       _("alias not set for redirdev device"));
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &redirdev->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, redirdev->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveRedirdevDevice(driver, vm, redirdev);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepNet(virQEMUDriverPtr driver,
0a7476
-                        virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepNet(virDomainObjPtr vm,
0a7476
                         virDomainNetDefPtr match,
0a7476
-                        virDomainNetDefPtr *detach,
0a7476
-                        bool async)
0a7476
+                        virDomainNetDefPtr *detach)
0a7476
 {
0a7476
-    int detachidx, ret = -1;
0a7476
+    int detachidx;
0a7476
     virDomainNetDefPtr net = NULL;
0a7476
 
0a7476
     if ((detachidx = virDomainNetFindIdx(vm->def, match)) < 0)
0a7476
-        goto cleanup;
0a7476
+        return -1;
0a7476
 
0a7476
     *detach = net = vm->def->nets[detachidx];
0a7476
 
0a7476
-    if (qemuIsMultiFunctionDevice(vm->def, &net->info)) {
0a7476
-        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
-                       _("cannot hot unplug multifunction PCI device: %s"),
0a7476
-                       net->ifname);
0a7476
-        goto cleanup;
0a7476
-    }
0a7476
+    return 0;
0a7476
+}
0a7476
 
0a7476
-    if (!net->info.alias) {
0a7476
-        if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
0a7476
-            goto cleanup;
0a7476
-    }
0a7476
 
0a7476
+static void
0a7476
+qemuDomainDetachShutdownNet(virDomainNetDefPtr net)
0a7476
+{
0a7476
+/*
0a7476
+ * These operations are in a separate function from
0a7476
+ * qemuDomainDetachPrepNet() because they can't be done until after
0a7476
+ * we've validated that this device really can be removed - in
0a7476
+ * particular we need to check for multifunction PCI devices and
0a7476
+ * presence of a device alias, which isn't done until *after* the
0a7476
+ * return from qemuDomainDetachPrepNet(). Since we've already passed
0a7476
+ * the "point of no return", we ignore any errors, and trudge ahead
0a7476
+ * with shutting down and detaching the device even if there is an
0a7476
+ * error in one of these functions.
0a7476
+ */
0a7476
     if (virDomainNetGetActualBandwidth(net) &&
0a7476
         virNetDevSupportBandwidth(virDomainNetGetActualType(net)) &&
0a7476
         virNetDevBandwidthClear(net->ifname) < 0)
0a7476
@@ -5426,32 +5274,6 @@ qemuDomainDetachPrepNet(virQEMUDriverPtr driver,
0a7476
      * the parent device offline)
0a7476
      */
0a7476
     ignore_value(qemuInterfaceStopDevice(net));
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &net->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, net->info.alias) < 0) {
0a7476
-        if (virDomainObjIsActive(vm)) {
0a7476
-            /* the audit message has a different format for hostdev network devices */
0a7476
-            if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV)
0a7476
-                virDomainAuditHostdev(vm, virDomainNetGetActualHostdev(net), "detach", false);
0a7476
-            else
0a7476
-                virDomainAuditNet(vm, net, NULL, "detach", false);
0a7476
-        }
0a7476
-        goto cleanup;
0a7476
-    }
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveNetDevice(driver, vm, net);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
 }
0a7476
 
0a7476
 
0a7476
@@ -5514,15 +5336,12 @@ qemuDomainDetachDeviceChr(virQEMUDriverPtr driver,
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepRNG(virQEMUDriverPtr driver,
0a7476
-                        virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepRNG(virDomainObjPtr vm,
0a7476
                         virDomainRNGDefPtr match,
0a7476
-                        virDomainRNGDefPtr *detach,
0a7476
-                        bool async)
0a7476
+                        virDomainRNGDefPtr *detach)
0a7476
 {
0a7476
     ssize_t idx;
0a7476
     virDomainRNGDefPtr rng;
0a7476
-    int ret = -1;
0a7476
 
0a7476
     if ((idx = virDomainRNGFind(vm->def, match)) < 0) {
0a7476
         virReportError(VIR_ERR_DEVICE_MISSING,
0a7476
@@ -5534,42 +5353,17 @@ qemuDomainDetachPrepRNG(virQEMUDriverPtr driver,
0a7476
 
0a7476
     *detach = rng = vm->def->rngs[idx];
0a7476
 
0a7476
-    if (!rng->info.alias) {
0a7476
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
0a7476
-                       _("alias not set for RNG device"));
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &rng->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, rng->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveRNGDevice(driver, vm, rng);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
-qemuDomainDetachPrepMemory(virQEMUDriverPtr driver,
0a7476
-                           virDomainObjPtr vm,
0a7476
+qemuDomainDetachPrepMemory(virDomainObjPtr vm,
0a7476
                            virDomainMemoryDefPtr match,
0a7476
-                           virDomainMemoryDefPtr *detach,
0a7476
-                           bool async)
0a7476
+                           virDomainMemoryDefPtr *detach)
0a7476
 {
0a7476
     virDomainMemoryDefPtr mem;
0a7476
     int idx;
0a7476
-    int ret = -1;
0a7476
 
0a7476
     qemuDomainMemoryDeviceAlignSize(vm->def, match);
0a7476
 
0a7476
@@ -5583,40 +5377,16 @@ qemuDomainDetachPrepMemory(virQEMUDriverPtr driver,
0a7476
 
0a7476
     *detach = mem = vm->def->mems[idx];
0a7476
 
0a7476
-    if (!mem->info.alias) {
0a7476
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
0a7476
-                       _("alias for the memory device was not found"));
0a7476
-        return -1;
0a7476
-    }
0a7476
-
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &mem->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, mem->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveMemoryDevice(driver, vm, mem);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
 qemuDomainDetachPrepInput(virDomainObjPtr vm,
0a7476
                           virDomainInputDefPtr match,
0a7476
-                          virDomainInputDefPtr *detach,
0a7476
-                          bool async)
0a7476
+                          virDomainInputDefPtr *detach)
0a7476
 {
0a7476
     virDomainInputDefPtr input;
0a7476
-    int ret = -1;
0a7476
     int idx;
0a7476
 
0a7476
     if ((idx = virDomainInputDefFind(vm->def, match)) < 0) {
0a7476
@@ -5641,35 +5411,16 @@ qemuDomainDetachPrepInput(virDomainObjPtr vm,
0a7476
         break;
0a7476
     }
0a7476
 
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &input->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, input->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveInputDevice(vm, input);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
 static int
0a7476
 qemuDomainDetachPrepVsock(virDomainObjPtr vm,
0a7476
                           virDomainVsockDefPtr match,
0a7476
-                          virDomainVsockDefPtr *detach,
0a7476
-                          bool async)
0a7476
+                          virDomainVsockDefPtr *detach)
0a7476
 {
0a7476
     virDomainVsockDefPtr vsock;
0a7476
-    int ret = -1;
0a7476
-
0a7476
 
0a7476
     *detach = vsock = vm->def->vsock;
0a7476
     if (!vsock ||
0a7476
@@ -5679,23 +5430,7 @@ qemuDomainDetachPrepVsock(virDomainObjPtr vm,
0a7476
         return -1;
0a7476
     }
0a7476
 
0a7476
-    if (!async)
0a7476
-        qemuDomainMarkDeviceForRemoval(vm, &vsock->info);
0a7476
-
0a7476
-    if (qemuDomainDeleteDevice(vm, vsock->info.alias) < 0)
0a7476
-        goto cleanup;
0a7476
-
0a7476
-    if (async) {
0a7476
-        ret = 0;
0a7476
-    } else {
0a7476
-        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
-            ret = qemuDomainRemoveVsockDevice(vm, vsock);
0a7476
-    }
0a7476
-
0a7476
- cleanup:
0a7476
-    if (!async)
0a7476
-        qemuDomainResetDeviceRemoval(vm);
0a7476
-    return ret;
0a7476
+    return 0;
0a7476
 }
0a7476
 
0a7476
 
0a7476
@@ -5730,6 +5465,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
0a7476
                            bool async)
0a7476
 {
0a7476
     virDomainDeviceDef detach = { .type = match->type };
0a7476
+    virDomainDeviceInfoPtr info = NULL;
0a7476
     int ret = -1;
0a7476
 
0a7476
     switch ((virDomainDeviceType)match->type) {
0a7476
@@ -5752,68 +5488,68 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
0a7476
          * assure it is okay to detach the device.
0a7476
          */
0a7476
     case VIR_DOMAIN_DEVICE_DISK:
0a7476
-        if (qemuDomainDetachPrepDisk(driver, vm, match->data.disk,
0a7476
-                                     &detach.data.disk, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepDisk(vm, match->data.disk,
0a7476
+                                     &detach.data.disk) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_CONTROLLER:
0a7476
-        if (qemuDomainDetachPrepController(driver, vm, match->data.controller,
0a7476
-                                           &detach.data.controller, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepController(vm, match->data.controller,
0a7476
+                                           &detach.data.controller) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_NET:
0a7476
-        if (qemuDomainDetachPrepNet(driver, vm, match->data.net,
0a7476
-                                    &detach.data.net, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepNet(vm, match->data.net,
0a7476
+                                    &detach.data.net) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_HOSTDEV:
0a7476
-        if (qemuDomainDetachPrepHostdev(driver, vm, match->data.hostdev,
0a7476
-                                        &detach.data.hostdev, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepHostdev(vm, match->data.hostdev,
0a7476
+                                        &detach.data.hostdev) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_RNG:
0a7476
-        if (qemuDomainDetachPrepRNG(driver, vm, match->data.rng,
0a7476
-                                    &detach.data.rng, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepRNG(vm, match->data.rng,
0a7476
+                                    &detach.data.rng) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_MEMORY:
0a7476
-        if (qemuDomainDetachPrepMemory(driver, vm, match->data.memory,
0a7476
-                                       &detach.data.memory, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepMemory(vm, match->data.memory,
0a7476
+                                       &detach.data.memory) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_SHMEM:
0a7476
-        if (qemuDomainDetachPrepShmem(driver, vm, match->data.shmem,
0a7476
-                                      &detach.data.shmem, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepShmem(vm, match->data.shmem,
0a7476
+                                      &detach.data.shmem) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_WATCHDOG:
0a7476
-        if (qemuDomainDetachPrepWatchdog(driver, vm, match->data.watchdog,
0a7476
-                                         &detach.data.watchdog, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepWatchdog(vm, match->data.watchdog,
0a7476
+                                         &detach.data.watchdog) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_INPUT:
0a7476
         if (qemuDomainDetachPrepInput(vm, match->data.input,
0a7476
-                                      &detach.data.input, async) < 0) {
0a7476
+                                      &detach.data.input) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_REDIRDEV:
0a7476
-        if (qemuDomainDetachPrepRedirdev(driver, vm, match->data.redirdev,
0a7476
-                                         &detach.data.redirdev, async) < 0) {
0a7476
+        if (qemuDomainDetachPrepRedirdev(vm, match->data.redirdev,
0a7476
+                                         &detach.data.redirdev) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
     case VIR_DOMAIN_DEVICE_VSOCK:
0a7476
         if (qemuDomainDetachPrepVsock(vm, match->data.vsock,
0a7476
-                                      &detach.data.vsock, async) < 0) {
0a7476
+                                      &detach.data.vsock) < 0) {
0a7476
             return -1;
0a7476
         }
0a7476
         break;
0a7476
@@ -5837,7 +5573,75 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
0a7476
         return -1;
0a7476
     }
0a7476
 
0a7476
-    ret = 0;
0a7476
+    /* "detach" now points to the actual device we want to detach */
0a7476
+
0a7476
+    if (!(info = virDomainDeviceGetInfo(&detach))) {
0a7476
+        /*
0a7476
+         * This should never happen, since all of the device types in
0a7476
+         * the switch cases that end with a "break" instead of a
0a7476
+         * return have a virDeviceInfo in them.
0a7476
+         */
0a7476
+        virReportError(VIR_ERR_INTERNAL_ERROR,
0a7476
+                       _("device of type '%s' has no device info"),
0a7476
+                       virDomainDeviceTypeToString(detach.type));
0a7476
+        return -1;
0a7476
+    }
0a7476
+
0a7476
+
0a7476
+    /* Make generic validation checks common to all device types */
0a7476
+
0a7476
+    if (!info->alias) {
0a7476
+        virReportError(VIR_ERR_INTERNAL_ERROR,
0a7476
+                       _("Cannot detach %s device with no alias"),
0a7476
+                       virDomainDeviceTypeToString(detach.type));
0a7476
+        return -1;
0a7476
+    }
0a7476
+
0a7476
+    if (qemuIsMultiFunctionDevice(vm->def, info)) {
0a7476
+        virReportError(VIR_ERR_OPERATION_FAILED,
0a7476
+                       _("cannot hot unplug %s device with multifunction PCI guest address: "
0a7476
+                         "%.4x:%.2x:%.2x.%.1x"),
0a7476
+                       virDomainDeviceTypeToString(detach.type),
0a7476
+                       info->addr.pci.domain, info->addr.pci.bus,
0a7476
+                       info->addr.pci.slot, info->addr.pci.function);
0a7476
+        return -1;
0a7476
+    }
0a7476
+
0a7476
+
0a7476
+    /*
0a7476
+     * Do any device-specific shutdown that should be
0a7476
+     * done after all validation checks, but before issuing the qemu
0a7476
+     * command to delete the device. For now, the only type of device
0a7476
+     * that has such shutdown needs is the net device.
0a7476
+     */
0a7476
+    if (detach.type == VIR_DOMAIN_DEVICE_NET)
0a7476
+        qemuDomainDetachShutdownNet(detach.data.net);
0a7476
+
0a7476
+
0a7476
+    /*
0a7476
+     * Issue the qemu monitor command to delete the device (based on
0a7476
+     * its alias), and optionally wait a short time in case the
0a7476
+     * DEVICE_DELETED event arrives from qemu right away.
0a7476
+     */
0a7476
+    if (!async)
0a7476
+        qemuDomainMarkDeviceForRemoval(vm, info);
0a7476
+
0a7476
+    if (qemuDomainDeleteDevice(vm, info->alias) < 0) {
0a7476
+        if (virDomainObjIsActive(vm))
0a7476
+            qemuDomainRemoveAuditDevice(vm, &detach, false);
0a7476
+        goto cleanup;
0a7476
+    }
0a7476
+
0a7476
+    if (async) {
0a7476
+        ret = 0;
0a7476
+    } else {
0a7476
+        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
0a7476
+            ret = qemuDomainRemoveDevice(driver, vm, &detach);
0a7476
+    }
0a7476
+
0a7476
+ cleanup:
0a7476
+    if (!async)
0a7476
+        qemuDomainResetDeviceRemoval(vm);
0a7476
 
0a7476
     return ret;
0a7476
 }
0a7476
-- 
0a7476
2.21.0
0a7476