--- src/qemu/qemu_domain.h | 2 + src/qemu/qemu_hotplug.c | 101 +++++++++++++++++++++++++++++++++++++++++++++--- src/qemu/qemu_hotplug.h | 3 ++ src/qemu/qemu_process.c | 41 ++++++++++++++++++++ 4 files changed, 142 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 750841f..ba273ed 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -168,6 +168,8 @@ struct _qemuDomainObjPrivate { size_t ncleanupCallbacks_max; virCgroupPtr cgroup; + + const char *deletingDevice; /* alias of the device that is being deleted */ }; typedef enum { diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 169cce2..8c2f756 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2347,6 +2347,49 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, } +void +qemuDomainRemoveDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + switch ((virDomainDeviceType) dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk); + break; + case VIR_DOMAIN_DEVICE_CONTROLLER: + qemuDomainRemoveControllerDevice(driver, vm, dev->data.controller); + break; + case VIR_DOMAIN_DEVICE_NET: + qemuDomainRemoveNetDevice(driver, vm, dev->data.net); + break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev); + break; + + case VIR_DOMAIN_DEVICE_NONE: + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_FS: + case VIR_DOMAIN_DEVICE_INPUT: + case VIR_DOMAIN_DEVICE_SOUND: + case VIR_DOMAIN_DEVICE_VIDEO: + case VIR_DOMAIN_DEVICE_WATCHDOG: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + case VIR_DOMAIN_DEVICE_CHR: + case VIR_DOMAIN_DEVICE_MEMBALLOON: + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_RNG: + case VIR_DOMAIN_DEVICE_LAST: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("don't know how to remove a %s device"), + virDomainDeviceTypeToString(dev->type)); + break; + } +} + + int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainDiskDefPtr detach) @@ -2385,6 +2428,11 @@ int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver, QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) goto cleanup; + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info.alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) { @@ -2406,10 +2454,12 @@ int qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver, qemuDomainObjExitMonitor(driver, vm); - qemuDomainRemoveDiskDevice(driver, vm, detach); + if (!priv->deletingDevice) + qemuDomainRemoveDiskDevice(driver, vm, detach); ret = 0; cleanup: + priv->deletingDevice = NULL; VIR_FREE(drivestr); return ret; } @@ -2442,6 +2492,11 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) goto cleanup; + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info.alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) { qemuDomainObjExitMonitor(driver, vm); @@ -2454,10 +2509,12 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, qemuDomainObjExitMonitor(driver, vm); - qemuDomainRemoveDiskDevice(driver, vm, detach); + if (!priv->deletingDevice) + qemuDomainRemoveDiskDevice(driver, vm, detach); ret = 0; cleanup: + priv->deletingDevice = NULL; VIR_FREE(drivestr); return ret; } @@ -2557,6 +2614,11 @@ int qemuDomainDetachPciControllerDevice(virQEMUDriverPtr driver, goto cleanup; } + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info.alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) { @@ -2572,11 +2634,13 @@ int qemuDomainDetachPciControllerDevice(virQEMUDriverPtr driver, } qemuDomainObjExitMonitor(driver, vm); - qemuDomainRemoveControllerDevice(driver, vm, detach); + if (!priv->deletingDevice) + qemuDomainRemoveControllerDevice(driver, vm, detach); ret = 0; cleanup: + priv->deletingDevice = NULL; return ret; } @@ -2604,6 +2668,11 @@ qemuDomainDetachHostPciDevice(virQEMUDriverPtr driver, return -1; } + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info->alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { ret = qemuMonitorDelDevice(priv->mon, detach->info->alias); @@ -2635,6 +2704,11 @@ qemuDomainDetachHostUsbDevice(virQEMUDriverPtr driver, return -1; } + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info->alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); ret = qemuMonitorDelDevice(priv->mon, detach->info->alias); qemuDomainObjExitMonitor(driver, vm); @@ -2670,6 +2744,11 @@ qemuDomainDetachHostScsiDevice(virQEMUDriverPtr driver, if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, detach, priv->qemuCaps))) goto cleanup; + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info->alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if ((ret = qemuMonitorDelDevice(priv->mon, detach->info->alias)) == 0) { if ((ret = qemuMonitorDriveDel(priv->mon, drvstr)) < 0) { @@ -2697,6 +2776,7 @@ qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr detach) { + qemuDomainObjPrivatePtr priv = vm->privateData; int ret = -1; switch (detach->source.subsys.type) { @@ -2718,9 +2798,11 @@ qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver, if (ret < 0) virDomainAuditHostdev(vm, detach, "detach", false); - else + else if (!priv->deletingDevice) qemuDomainRemoveHostDevice(driver, vm, detach); + priv->deletingDevice = NULL; + return ret; } @@ -2851,6 +2933,11 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver, if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) goto cleanup; + if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + priv->deletingDevice = detach->info.alias; + else + priv->deletingDevice = NULL; + qemuDomainObjEnterMonitor(driver, vm); if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) { @@ -2883,9 +2970,13 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver, } qemuDomainObjExitMonitor(driver, vm); - qemuDomainRemoveNetDevice(driver, vm, detach); + if (!priv->deletingDevice) + qemuDomainRemoveNetDevice(driver, vm, detach); + ret = 0; + cleanup: + priv->deletingDevice = NULL; VIR_FREE(hostnet_name); return ret; } diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index da802ee..56acb1a 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -105,5 +105,8 @@ int qemuDomainDetachLease(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainLeaseDefPtr lease); +void qemuDomainRemoveDevice(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev); #endif /* __QEMU_HOTPLUG_H__ */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 574abf2..d73bc70 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1313,6 +1313,46 @@ cleanup: } +static int +qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *devAlias) +{ + virQEMUDriverPtr driver = qemu_driver; + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + qemuDomainObjPrivatePtr priv; + virDomainDeviceDef dev; + + virObjectLock(vm); + + VIR_DEBUG("Device %s removed from domain %p %s", + devAlias, vm, vm->def->name); + + priv = vm->privateData; + + if (STREQ_NULLABLE(priv->deletingDevice, devAlias)) { + /* We got this event before the command that requested removal of + * devAlias returned. Clear deletingDevice so that the unplugging + * code know it has to remove the device. + */ + priv->deletingDevice = NULL; + } else { + if (virDomainDefFindDevice(vm->def, devAlias, &dev) < 0) + goto cleanup; + + qemuDomainRemoveDevice(driver, vm, &dev); + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + VIR_WARN("unable to save domain status with balloon change"); + } + +cleanup: + virObjectUnlock(vm); + virObjectUnref(cfg); + return 0; +} + + static qemuMonitorCallbacks monitorCallbacks = { .destroy = qemuProcessHandleMonitorDestroy, .eofNotify = qemuProcessHandleMonitorEOF, @@ -1333,6 +1373,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .domainBalloonChange = qemuProcessHandleBalloonChange, .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk, .domainGuestPanic = qemuProcessHandleGuestPanic, + .domainDeviceDeleted = qemuProcessHandleDeviceDeleted, }; static int -- 1.8.3.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list