[libvirt] [PATCH v3 REBASE 02/12] qemu: track hostdev delete intention

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Tue Oct 15 14:29:46 UTC 2019


So we are going to support replug of usb device on host. We need to
delete device from qemu when the device is unplugged on host and to add
device when the device is plugged back. As to deleting let's use
same code as when we detach device from domain. But we need to keep
the usb hostdev etc in libvirt config when handle DEVICE_DELETED event
from qemu. For this purpose let's save delete intention in device config.

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
---
 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 da3eff242b..0a16413852 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -328,6 +328,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 {
@@ -345,6 +358,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 681b26814b..ca40879977 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9078,7 +9078,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)
@@ -9167,7 +9167,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 88984dff67..4f7858da71 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -5351,7 +5351,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;
@@ -5423,6 +5424,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;
 }
 
@@ -5724,7 +5739,8 @@ int
 qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                            virDomainDeviceDefPtr match,
                            virQEMUDriverPtr driver,
-                           bool async)
+                           bool async,
+                           bool unplug)
 {
     virDomainDeviceDef detach = { .type = match->type };
     virDomainDeviceInfoPtr info = NULL;
@@ -5769,7 +5785,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 6d2cd34dbc..647f617355 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 76b131295a..ec58d89e01 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -158,7 +158,7 @@ testQemuHotplugDetach(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_WATCHDOG:
     case VIR_DOMAIN_DEVICE_HOSTDEV:
-        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




More information about the libvir-list mailing list