|
|
99cbc7 |
From ac1770917c5f6020ccb5b6247f3eeb9f50a67903 Mon Sep 17 00:00:00 2001
|
|
|
99cbc7 |
Message-Id: <ac1770917c5f6020ccb5b6247f3eeb9f50a67903@dist-git>
|
|
|
99cbc7 |
From: Laine Stump <laine@laine.org>
|
|
|
99cbc7 |
Date: Thu, 11 Apr 2019 15:14:53 -0400
|
|
|
99cbc7 |
Subject: [PATCH] qemu_hotplug: delay sending DEVICE_REMOVED event until after
|
|
|
99cbc7 |
*all* teardown
|
|
|
99cbc7 |
|
|
|
99cbc7 |
The VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED event is sent after qemu has
|
|
|
99cbc7 |
responded to a device_del command with a DEVICE_DELETED event. Before
|
|
|
99cbc7 |
queuing the event, *some* of the final teardown of the device's
|
|
|
99cbc7 |
trappings in libvirt is done, but not *all* of it. As a result, an
|
|
|
99cbc7 |
application may receive and process the DEVICE_REMOVED event before
|
|
|
99cbc7 |
libvirt has really finished with it.
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Usually this doesn't cause a problem, but it can - in the case of the
|
|
|
99cbc7 |
bug report referenced below, vdsm is assigning a PCI device to a guest
|
|
|
99cbc7 |
with managed='no', using livirt's virNodeDeviceDetachFlags() and
|
|
|
99cbc7 |
virNodeDeviceReAttach() APIs. Immediately after receiving a
|
|
|
99cbc7 |
DEVICE_REMOVED event from libvirt signalling that the device had been
|
|
|
99cbc7 |
successfully unplugged, vdsm would cal virNodeDeviceReAttach() to
|
|
|
99cbc7 |
unbind the device from vfio-pci and rebind it to the host driverm but
|
|
|
99cbc7 |
because the event was received before libvirt had completely finished
|
|
|
99cbc7 |
processing the removal, that device was still on the "activeDevs"
|
|
|
99cbc7 |
list, and so virNodeDeviceReAttach() failed.
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Experimentation with additional debug logs proved that libvirt would
|
|
|
99cbc7 |
always end up dispatching the DEVICE_REMOVED event before it had
|
|
|
99cbc7 |
removed the device from activeDevs (with a *much* greater difference
|
|
|
99cbc7 |
with managed='yes', since in that case the re-binding of the device
|
|
|
99cbc7 |
occurred after queuing the device).
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Although the case of hostdev devices is the most extreme (since there
|
|
|
99cbc7 |
is so much involved in tearing down the device), *all* device types
|
|
|
99cbc7 |
suffer from the same problem - the DEVICE_REMOVED event is queued very
|
|
|
99cbc7 |
early in the qemuDomainRemove*Device() function for all of them,
|
|
|
99cbc7 |
resulting in a possibility of any application receiving the event
|
|
|
99cbc7 |
before libvirt has really finished with the device.
|
|
|
99cbc7 |
|
|
|
99cbc7 |
The solution is to save the device's alias (which is the only piece of
|
|
|
99cbc7 |
info from the device object that is needed for the event) at the
|
|
|
99cbc7 |
beginning of processing the device removal, and then queue the event
|
|
|
99cbc7 |
as a final act before returning. Since all of the
|
|
|
99cbc7 |
qemuDomainRemove*Device() functions (except
|
|
|
99cbc7 |
qemuDomainRemoveChrDevice()) are now called exclusively from
|
|
|
99cbc7 |
qemuDomainRemoveDevice() (which selects which of the subordinates to
|
|
|
99cbc7 |
call in a switch statement based on the type of device), the shortest
|
|
|
99cbc7 |
route to a solution is to doing the saving of alias, and later
|
|
|
99cbc7 |
queueing of the event, in the higher level qemuDomainRemoveDevice(),
|
|
|
99cbc7 |
and just completely remove the event-related code from all the
|
|
|
99cbc7 |
subordinate functions.
|
|
|
99cbc7 |
|
|
|
99cbc7 |
The single exception to this, as mentioned before, is
|
|
|
99cbc7 |
qemuDomainRemoveChrDevice(), which is still called from somewhere
|
|
|
99cbc7 |
other than qemuDomainRemoveDevice() (and has a separate arg used to
|
|
|
99cbc7 |
trigger different behavior when the chr device has targetType ==
|
|
|
99cbc7 |
GUESTFWD), so it must keep its original behavior intact, and must be
|
|
|
99cbc7 |
treated differently by qemuDomainRemoveDevice() (similar to the way
|
|
|
99cbc7 |
that qemuDomainDetachDeviceLive() treats chr and lease devices
|
|
|
99cbc7 |
differently from all the others).
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Signed-off-by: Laine Stump <laine@laine.org>
|
|
|
99cbc7 |
ACKed-by: Peter Krempa <pkrempa@redhat.com>
|
|
|
99cbc7 |
(cherry picked from commit 78b03a7770f1822458be3e0769538dfc92b34803)
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Resolves: https://bugzilla.redhat.com/1658198
|
|
|
99cbc7 |
Signed-off-by: Laine Stump <laine@redhat.com>
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Conflicts:
|
|
|
99cbc7 |
src/qemu/qemu_hotplug.c:
|
|
|
99cbc7 |
* some code around a removed event queuing had been
|
|
|
99cbc7 |
moved into a helper function upstream.
|
|
|
99cbc7 |
|
|
|
99cbc7 |
* upstream patch used VIR_AUTOFREE, which isn't in 4.5.0
|
|
|
99cbc7 |
|
|
|
99cbc7 |
Signed-off-by: Laine Stump <laine@laine.org>
|
|
|
99cbc7 |
Message-Id: <20190411191453.24055-42-laine@redhat.com>
|
|
|
99cbc7 |
Acked-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
99cbc7 |
---
|
|
|
99cbc7 |
src/qemu/qemu_hotplug.c | 145 +++++++++++++++++++---------------------
|
|
|
99cbc7 |
1 file changed, 70 insertions(+), 75 deletions(-)
|
|
|
99cbc7 |
|
|
|
99cbc7 |
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
|
|
|
99cbc7 |
index ff88a827dd..103d3e59a7 100644
|
|
|
99cbc7 |
--- a/src/qemu/qemu_hotplug.c
|
|
|
99cbc7 |
+++ b/src/qemu/qemu_hotplug.c
|
|
|
99cbc7 |
@@ -3905,7 +3905,6 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
qemuDomainStorageSourcePrivatePtr diskPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src);
|
|
|
99cbc7 |
virDomainDeviceDef dev;
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
size_t i;
|
|
|
99cbc7 |
const char *src = virDomainDiskGetSource(disk);
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
@@ -3972,9 +3971,6 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
|
|
|
99cbc7 |
virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, disk->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if (prManaged && !prUsed)
|
|
|
99cbc7 |
qemuProcessKillManagedPRDaemon(vm);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
@@ -4003,19 +3999,14 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
|
|
|
99cbc7 |
|
|
|
99cbc7 |
static int
|
|
|
99cbc7 |
-qemuDomainRemoveControllerDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
- virDomainObjPtr vm,
|
|
|
99cbc7 |
+qemuDomainRemoveControllerDevice(virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainControllerDefPtr controller)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
size_t i;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
VIR_DEBUG("Removing controller %s from domain %p %s",
|
|
|
99cbc7 |
controller->info.alias, vm, vm->def->name);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, controller->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
for (i = 0; i < vm->def->ncontrollers; i++) {
|
|
|
99cbc7 |
if (vm->def->controllers[i] == controller) {
|
|
|
99cbc7 |
virDomainControllerRemove(vm->def, i);
|
|
|
99cbc7 |
@@ -4037,7 +4028,6 @@ qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
|
|
|
99cbc7 |
unsigned long long newmem = oldmem - mem->size;
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
char *backendAlias = NULL;
|
|
|
99cbc7 |
int rc;
|
|
|
99cbc7 |
int idx;
|
|
|
99cbc7 |
@@ -4059,9 +4049,6 @@ qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
if (rc < 0)
|
|
|
99cbc7 |
return -1;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, mem->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if ((idx = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
|
|
|
99cbc7 |
virDomainMemoryRemove(vm->def, idx);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
@@ -4141,7 +4128,6 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
99cbc7 |
virDomainNetDefPtr net = NULL;
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
size_t i;
|
|
|
99cbc7 |
int ret = -1;
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
@@ -4185,9 +4171,6 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
goto cleanup;
|
|
|
99cbc7 |
}
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, hostdev->info->alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET) {
|
|
|
99cbc7 |
net = hostdev->parent.data.net;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
@@ -4266,7 +4249,6 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
char *hostnet_name = NULL;
|
|
|
99cbc7 |
char *charDevAlias = NULL;
|
|
|
99cbc7 |
size_t i;
|
|
|
99cbc7 |
@@ -4322,9 +4304,6 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
|
|
|
99cbc7 |
virDomainAuditNet(vm, net, NULL, "detach", true);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, net->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
for (i = 0; i < vm->def->nnets; i++) {
|
|
|
99cbc7 |
if (vm->def->nets[i] == net) {
|
|
|
99cbc7 |
virDomainNetRemove(vm->def, i);
|
|
|
99cbc7 |
@@ -4408,11 +4387,16 @@ qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
if (qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
|
|
|
99cbc7 |
VIR_WARN("Unable to remove chr device from /dev");
|
|
|
99cbc7 |
|
|
|
99cbc7 |
+ qemuDomainReleaseDeviceAddress(vm, &chr->info, NULL);
|
|
|
99cbc7 |
+ qemuDomainChrRemove(vm->def, chr);
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ /* The caller does not emit the event, so we must do it here. Note
|
|
|
99cbc7 |
+ * that the event should be reported only after all backend
|
|
|
99cbc7 |
+ * teardown is completed.
|
|
|
99cbc7 |
+ */
|
|
|
99cbc7 |
event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
|
|
|
99cbc7 |
virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- qemuDomainReleaseDeviceAddress(vm, &chr->info, NULL);
|
|
|
99cbc7 |
- qemuDomainChrRemove(vm->def, chr);
|
|
|
99cbc7 |
virDomainChrDefFree(chr);
|
|
|
99cbc7 |
ret = 0;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
@@ -4427,7 +4411,6 @@ qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainRNGDefPtr rng)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
char *charAlias = NULL;
|
|
|
99cbc7 |
char *objAlias = NULL;
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
@@ -4469,9 +4452,6 @@ qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
if (qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
|
|
|
99cbc7 |
VIR_WARN("Unable to remove RNG device from /dev");
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, rng->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
|
|
|
99cbc7 |
virDomainRNGRemove(vm->def, idx);
|
|
|
99cbc7 |
qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
|
|
|
99cbc7 |
@@ -4496,7 +4476,6 @@ qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
char *charAlias = NULL;
|
|
|
99cbc7 |
char *memAlias = NULL;
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
- virObjectEventPtr event = NULL;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
VIR_DEBUG("Removing shmem device %s from domain %p %s",
|
|
|
99cbc7 |
shmem->info.alias, vm, vm->def->name);
|
|
|
99cbc7 |
@@ -4524,9 +4503,6 @@ qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
if (rc < 0)
|
|
|
99cbc7 |
goto cleanup;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, shmem->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
|
|
|
99cbc7 |
virDomainShmemDefRemove(vm->def, idx);
|
|
|
99cbc7 |
qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
|
|
|
99cbc7 |
@@ -4542,17 +4518,12 @@ qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
|
|
|
99cbc7 |
|
|
|
99cbc7 |
static int
|
|
|
99cbc7 |
-qemuDomainRemoveWatchdog(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
- virDomainObjPtr vm,
|
|
|
99cbc7 |
+qemuDomainRemoveWatchdog(virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainWatchdogDefPtr watchdog)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
- virObjectEventPtr event = NULL;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
VIR_DEBUG("Removing watchdog %s from domain %p %s",
|
|
|
99cbc7 |
watchdog->info.alias, vm, vm->def->name);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, watchdog->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
qemuDomainReleaseDeviceAddress(vm, &watchdog->info, NULL);
|
|
|
99cbc7 |
virDomainWatchdogDefFree(vm->def->watchdog);
|
|
|
99cbc7 |
vm->def->watchdog = NULL;
|
|
|
99cbc7 |
@@ -4564,16 +4535,11 @@ static int
|
|
|
99cbc7 |
qemuDomainRemoveInputDevice(virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainInputDefPtr dev)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
- qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
- virQEMUDriverPtr driver = priv->driver;
|
|
|
99cbc7 |
- virObjectEventPtr event = NULL;
|
|
|
99cbc7 |
size_t i;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
VIR_DEBUG("Removing input device %s from domain %p %s",
|
|
|
99cbc7 |
dev->info.alias, vm, vm->def->name);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, dev->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
for (i = 0; i < vm->def->ninputs; i++) {
|
|
|
99cbc7 |
if (vm->def->inputs[i] == dev)
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
@@ -4598,15 +4564,9 @@ static int
|
|
|
99cbc7 |
qemuDomainRemoveVsockDevice(virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainVsockDefPtr dev)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
- qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
- virQEMUDriverPtr driver = priv->driver;
|
|
|
99cbc7 |
- virObjectEventPtr event = NULL;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
VIR_DEBUG("Removing vsock device %s from domain %p %s",
|
|
|
99cbc7 |
dev->info.alias, vm, vm->def->name);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, dev->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
qemuDomainReleaseDeviceAddress(vm, &dev->info, NULL);
|
|
|
99cbc7 |
virDomainVsockDefFree(vm->def->vsock);
|
|
|
99cbc7 |
vm->def->vsock = NULL;
|
|
|
99cbc7 |
@@ -4620,7 +4580,6 @@ qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
virDomainRedirdevDefPtr dev)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
99cbc7 |
- virObjectEventPtr event;
|
|
|
99cbc7 |
char *charAlias = NULL;
|
|
|
99cbc7 |
ssize_t idx;
|
|
|
99cbc7 |
int ret = -1;
|
|
|
99cbc7 |
@@ -4645,9 +4604,6 @@ qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
|
|
|
99cbc7 |
virDomainAuditRedirdev(vm, dev, "detach", true);
|
|
|
99cbc7 |
|
|
|
99cbc7 |
- event = virDomainEventDeviceRemovedNewFromObj(vm, dev->info.alias);
|
|
|
99cbc7 |
- virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
if ((idx = virDomainRedirdevDefFind(vm->def, dev)) >= 0)
|
|
|
99cbc7 |
virDomainRedirdevDefRemove(vm->def, idx);
|
|
|
99cbc7 |
qemuDomainReleaseDeviceAddress(vm, &dev->info, NULL);
|
|
|
99cbc7 |
@@ -4730,50 +4686,81 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
virDomainObjPtr vm,
|
|
|
99cbc7 |
virDomainDeviceDefPtr dev)
|
|
|
99cbc7 |
{
|
|
|
99cbc7 |
+ virDomainDeviceInfoPtr info;
|
|
|
99cbc7 |
+ virObjectEventPtr event;
|
|
|
99cbc7 |
+ char *alias = NULL;
|
|
|
99cbc7 |
int ret = -1;
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ /*
|
|
|
99cbc7 |
+ * save the alias to use when sending a DEVICE_REMOVED event after
|
|
|
99cbc7 |
+ * all other teardown is complete
|
|
|
99cbc7 |
+ */
|
|
|
99cbc7 |
+ if ((info = virDomainDeviceGetInfo(dev)) &&
|
|
|
99cbc7 |
+ VIR_STRDUP(alias, info->alias) < 0) {
|
|
|
99cbc7 |
+ goto cleanup;;
|
|
|
99cbc7 |
+ }
|
|
|
99cbc7 |
+ info = NULL;
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
switch ((virDomainDeviceType)dev->type) {
|
|
|
99cbc7 |
+ case VIR_DOMAIN_DEVICE_CHR:
|
|
|
99cbc7 |
+ /* We must return directly after calling
|
|
|
99cbc7 |
+ * qemuDomainRemoveChrDevice because it is called directly
|
|
|
99cbc7 |
+ * from other places, so it must be completely self-contained
|
|
|
99cbc7 |
+ * and can't take advantage of any common code at the end of
|
|
|
99cbc7 |
+ * qemuDomainRemoveDevice().
|
|
|
99cbc7 |
+ */
|
|
|
99cbc7 |
+ ret = qemuDomainRemoveChrDevice(driver, vm, dev->data.chr, true);
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ /*
|
|
|
99cbc7 |
+ * all of the following qemuDomainRemove*Device() functions
|
|
|
99cbc7 |
+ * are (and must be) only called from this function, so any
|
|
|
99cbc7 |
+ * code that is common to them all can be pulled out and put
|
|
|
99cbc7 |
+ * into this function.
|
|
|
99cbc7 |
+ */
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_DISK:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_CONTROLLER:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveControllerDevice(driver, vm, dev->data.controller);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveControllerDevice(vm, dev->data.controller) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_NET:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveNetDevice(driver, vm, dev->data.net);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveNetDevice(driver, vm, dev->data.net) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev);
|
|
|
99cbc7 |
- break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
- case VIR_DOMAIN_DEVICE_CHR:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveChrDevice(driver, vm, dev->data.chr, true);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_RNG:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_MEMORY:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_SHMEM:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_INPUT:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveInputDevice(vm, dev->data.input);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveInputDevice(vm, dev->data.input) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_REDIRDEV:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveRedirdevDevice(driver, vm, dev->data.redirdev);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveRedirdevDevice(driver, vm, dev->data.redirdev) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_WATCHDOG:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveWatchdog(driver, vm, dev->data.watchdog);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveWatchdog(vm, dev->data.watchdog) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
-
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_VSOCK:
|
|
|
99cbc7 |
- ret = qemuDomainRemoveVsockDevice(vm, dev->data.vsock);
|
|
|
99cbc7 |
+ if (qemuDomainRemoveVsockDevice(vm, dev->data.vsock) < 0)
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
break;
|
|
|
99cbc7 |
|
|
|
99cbc7 |
case VIR_DOMAIN_DEVICE_NONE:
|
|
|
99cbc7 |
@@ -4793,8 +4780,16 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
|
|
|
99cbc7 |
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
|
|
99cbc7 |
_("don't know how to remove a %s device"),
|
|
|
99cbc7 |
virDomainDeviceTypeToString(dev->type));
|
|
|
99cbc7 |
- break;
|
|
|
99cbc7 |
+ goto cleanup;
|
|
|
99cbc7 |
}
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ event = virDomainEventDeviceRemovedNewFromObj(vm, alias);
|
|
|
99cbc7 |
+ virObjectEventStateQueue(driver->domainEventState, event);
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ ret = 0;
|
|
|
99cbc7 |
+
|
|
|
99cbc7 |
+ cleanup:
|
|
|
99cbc7 |
+ VIR_FREE(alias);
|
|
|
99cbc7 |
return ret;
|
|
|
99cbc7 |
}
|
|
|
99cbc7 |
|
|
|
99cbc7 |
--
|
|
|
99cbc7 |
2.21.0
|
|
|
99cbc7 |
|