qemuDomainDetachDeviceLive is called when client asks for detaching
a device. We are going to call this function when usb device is
detached on node itself. The function itself requests qemu to detach
device from guest but as device detaching is asynchronous libvirt
config changes are done in DEVICE_DELETED event handler. As we
want to keep device in libvirt config if device detached from node
opposite to the case of client initiated detaching we need to
track the delete cause.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
src/conf/domain_conf.h | 9 +++++++++
src/qemu/qemu_driver.c | 4 ++--
src/qemu/qemu_hotplug.c | 21 ++++++++++++++++++++-
src/qemu/qemu_hotplug.h | 3 ++-
tests/qemuhotplugtest.c | 2 +-
5 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 33cef5b75c..49392d0286 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -326,6 +326,14 @@ struct _virDomainHostdevCaps {
} u;
};
+typedef enum {
+ VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_NONE = 0,
+ VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_CLIENT,
+ VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING,
+
+ VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_LAST
+} virDomainHostdevDeleteCauseType;
+
/* basic device for direct passthrough */
struct _virDomainHostdevDef {
@@ -343,6 +351,7 @@ struct _virDomainHostdevDef {
bool missing;
bool readonly;
bool shareable;
+ virDomainHostdevDeleteCauseType deleteCause;
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..08e60dcd0e 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -5721,7 +5721,8 @@ int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
virDomainDeviceDefPtr match,
virQEMUDriverPtr driver,
- bool async)
+ bool async,
+ bool reattaching)
{
virDomainDeviceDef detach = { .type = match->type };
virDomainDeviceInfoPtr info = NULL;
@@ -5880,6 +5881,24 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
goto cleanup;
}
+ if (detach.type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+ virDomainHostdevDefPtr hostdev = detach.data.hostdev;
+
+ /*
+ * Why having additional check in second branch? Suppose client
+ * asks for device detaching and we pass the intention to qemu
+ * but don't get DEVICE_DELETED event yet. Next USB is detached
+ * on node and we have this function called again. If we reset
+ * delete cause to 'reattaching' 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 (!reattaching)
+ hostdev->deleteCause = VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_CLIENT;
+ else if (hostdev->deleteCause != VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_CLIENT)
+ hostdev->deleteCause = VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING;
+ }
+
if (async) {
ret = 0;
} else {
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 896e6c7b98..bf812eab1a 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 reattaching);
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