We are going to call qemuDomainDetachDeviceLive when usb device is unplugged from host. But later when DEVICE_DELETED event is delivered we need to keep device in libvirt config. For this purpuse let's save delete intention in device config. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@xxxxxxxxxxxxx> --- src/conf/domain_conf.h | 14 ++++++++++++++ src/qemu/qemu_driver.c | 4 ++-- src/qemu/qemu_hotplug.c | 23 ++++++++++++++++++++--- src/qemu/qemu_hotplug.h | 3 ++- tests/qemuhotplugtest.c | 2 +- 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 33cef5b75c..19a5b21462 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -326,6 +326,19 @@ struct _virDomainHostdevCaps { } u; }; +typedef enum { + VIR_DOMAIN_HOSTDEV_DELETE_ACTION_NONE = 0, + /* delete associated device from libvirt config + * as intended by client API call */ + VIR_DOMAIN_HOSTDEV_DELETE_ACTION_DELETE, + /* keep associated device in libvirt config as + * qemu device is deleted as a result of unplugging + * device from host */ + VIR_DOMAIN_HOSTDEV_DELETE_ACTION_UNPLUG, + + VIR_DOMAIN_HOSTDEV_DELETE_ACTION_LAST +} virDomainHostdevDeleteActionType; + /* basic device for direct passthrough */ struct _virDomainHostdevDef { @@ -343,6 +356,7 @@ struct _virDomainHostdevDef { bool missing; bool readonly; bool shareable; + virDomainHostdevDeleteActionType deleteAction; union { virDomainHostdevSubsys subsys; virDomainHostdevCaps caps; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 78f5471b79..2378a2e7d0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9123,7 +9123,7 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr driver, if (flags & VIR_DOMAIN_AFFECT_LIVE) { int rc; - if ((rc = qemuDomainDetachDeviceLive(vm, dev_copy, driver, false)) < 0) + if ((rc = qemuDomainDetachDeviceLive(vm, dev_copy, driver, false, false)) < 0) goto cleanup; if (rc == 0 && qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) @@ -9212,7 +9212,7 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDriverPtr driver, if (virDomainDefFindDevice(def, alias, &dev, true) < 0) goto cleanup; - if ((rc = qemuDomainDetachDeviceLive(vm, &dev, driver, true)) < 0) + if ((rc = qemuDomainDetachDeviceLive(vm, &dev, driver, true, false)) < 0) goto cleanup; if (rc == 0 && qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 63acb9c451..559254b234 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5348,7 +5348,8 @@ qemuDomainDetachPrepController(virDomainObjPtr vm, static int qemuDomainDetachPrepHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr match, - virDomainHostdevDefPtr *detach) + virDomainHostdevDefPtr *detach, + bool unplug) { virDomainHostdevSubsysPtr subsys = &match->source.subsys; virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb; @@ -5420,6 +5421,20 @@ qemuDomainDetachPrepHostdev(virDomainObjPtr vm, return -1; } + /* + * Why having additional check in second branch? Suppose client + * asks for device detaching and we delete device from qemu + * but don't get DEVICE_DELETED event yet. Next USB is unplugged + * from host and we have this function called again. If we reset + * delete action to 'unplug' then device will be left in + * libvirt config after handling DEVICE_DELETED event while + * it should not as client asked to detach the device before. + */ + if (!unplug) + hostdev->deleteAction = VIR_DOMAIN_HOSTDEV_DELETE_ACTION_DELETE; + else if (hostdev->deleteAction != VIR_DOMAIN_HOSTDEV_DELETE_ACTION_DELETE) + hostdev->deleteAction = VIR_DOMAIN_HOSTDEV_DELETE_ACTION_UNPLUG; + return 0; } @@ -5721,7 +5736,8 @@ int qemuDomainDetachDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr match, virQEMUDriverPtr driver, - bool async) + bool async, + bool unplug) { virDomainDeviceDef detach = { .type = match->type }; virDomainDeviceInfoPtr info = NULL; @@ -5766,7 +5782,8 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm, break; case VIR_DOMAIN_DEVICE_HOSTDEV: if (qemuDomainDetachPrepHostdev(vm, match->data.hostdev, - &detach.data.hostdev) < 0) { + &detach.data.hostdev, + unplug) < 0) { return -1; } break; diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 896e6c7b98..f7ebf3f505 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -116,7 +116,8 @@ int qemuDomainAttachRNGDevice(virQEMUDriverPtr driver, int qemuDomainDetachDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr match, virQEMUDriverPtr driver, - bool async); + bool async, + bool unplug); void qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver, virDomainObjPtr vm, diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index b6aad330a9..ef91d4f131 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -151,7 +151,7 @@ testQemuHotplugDetach(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_SHMEM: case VIR_DOMAIN_DEVICE_WATCHDOG: - ret = qemuDomainDetachDeviceLive(vm, dev, &driver, async); + ret = qemuDomainDetachDeviceLive(vm, dev, &driver, async, false); break; default: VIR_TEST_VERBOSE("device type '%s' cannot be detached", -- 2.23.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list