|
|
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 |
|