[libvirt] [PATCH 3/6] qemu: handle usb hostdev add/del on device DELETED_EVENT

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Fri Aug 30 12:08:31 UTC 2019


Now device DELETED_EVENT can have 2 causes. First is detaching device by
client just as before. Second is attaching/detaching hostdev assigned to
guest on node. In the latter case we reattach hostdev to guest.

When device is detached from node we remove device from qemu and insert
new dummy one with unset bus and device values and have missing flag set
to true. This is on par with case when we start domain with
startupPolicy = optional and device is missing on node.

When device is attached to node back we remove dummy device from qemu
and insert proper one with discovered bus and device and missing flag is
appropriately set to false.

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
---
 src/qemu/qemu_driver.c  | 12 ++-----
 src/qemu/qemu_hotplug.c | 73 ++++++++++++++++++++++++++++++++++-------
 src/qemu/qemu_hotplug.h |  4 +++
 src/util/virhostdev.c   |  6 ++--
 4 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 33b75a3c71..352f6d0376 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4677,7 +4677,6 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
                           const char *devAlias)
 {
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    virDomainDeviceDef dev;
 
     VIR_DEBUG("Removing device %s from domain %p %s",
               devAlias, vm, vm->def->name);
@@ -4690,15 +4689,10 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
         goto endjob;
     }
 
-    if (STRPREFIX(devAlias, "vcpu")) {
+    if (STRPREFIX(devAlias, "vcpu"))
         qemuDomainRemoveVcpuAlias(driver, vm, devAlias);
-    } else {
-        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
-            goto endjob;
-
-        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
-            goto endjob;
-    }
+    else if (qemuDomainRemoveDeviceAlias(driver, vm, devAlias) < 0)
+        goto endjob;
 
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
         VIR_WARN("unable to save domain status after removing device %s",
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 08e60dcd0e..197b2b2fd7 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2437,8 +2437,10 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
     bool teardownlabel = false;
     bool teardowndevice = false;
     int ret = -1;
+    bool reattaching = hostdev->deleteCause == VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING;
 
-    if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
+    if (!reattaching &&
+        virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
         return -1;
 
     if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
@@ -2463,7 +2465,7 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
     if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
         goto cleanup;
 
-    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
+    if (!reattaching && VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
         goto cleanup;
 
     qemuDomainObjEnterMonitor(driver, vm);
@@ -2476,7 +2478,8 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
     if (ret < 0)
         goto cleanup;
 
-    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
+    if (!reattaching)
+        vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
 
     ret = 0;
  cleanup:
@@ -2491,7 +2494,8 @@ qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
             VIR_WARN("Unable to remove host device from /dev");
         if (added)
             qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
-        virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
+        if (!reattaching)
+            virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
     }
     VIR_FREE(devstr);
     return ret;
@@ -4366,7 +4370,8 @@ qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
                               virDomainHostdevDefPtr hostdev)
 {
     qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
-    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
+    if (hostdev->deleteCause != VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING)
+        qemuDomainReleaseDeviceAddress(vm, hostdev->info);
 }
 
 static void
@@ -4408,6 +4413,7 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
     char *drivealias = NULL;
     char *objAlias = NULL;
     bool is_vfio = false;
+    bool reattaching = hostdev->deleteCause == VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING;
 
     VIR_DEBUG("Removing host device %s from domain %p %s",
               hostdev->info->alias, vm, vm->def->name);
@@ -4454,16 +4460,25 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
         }
     }
 
-    for (i = 0; i < vm->def->nhostdevs; i++) {
-        if (vm->def->hostdevs[i] == hostdev) {
-            virDomainHostdevRemove(vm->def, i);
-            break;
+    if (!reattaching) {
+        for (i = 0; i < vm->def->nhostdevs; i++) {
+            if (vm->def->hostdevs[i] == hostdev) {
+                virDomainHostdevRemove(vm->def, i);
+                break;
+            }
         }
     }
 
     virDomainAuditHostdev(vm, hostdev, "detach", true);
 
-    if (!is_vfio &&
+    /*
+     * In case of reattaching (when usb is detached from host) the attempt to
+     * restore label will fail. But we don't need to restore the label! In case
+     * of separate mount namespace for the domain we remove device file later
+     * in this function. In case of global mount namespace the device file is
+     * deleted or being deleted by systemd.
+     */
+    if (!is_vfio && !reattaching &&
         qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
         VIR_WARN("Failed to restore host device labelling");
 
@@ -4497,7 +4512,13 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
         break;
     }
 
-    virDomainHostdevDefFree(hostdev);
+    if (reattaching) {
+        virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
+        usbsrc->bus = 0;
+        usbsrc->device = 0;
+    } else {
+        virDomainHostdevDefFree(hostdev);
+    }
 
     if (net) {
         if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
@@ -6565,3 +6586,33 @@ qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
     virBitmapFree(livevcpus);
     return ret;
 }
+
+
+int
+qemuDomainRemoveDeviceAlias(virQEMUDriverPtr driver,
+                            virDomainObjPtr vm,
+                            const char *devAlias)
+{
+    virDomainDeviceDef dev;
+
+    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
+        return -1;
+
+    if (dev.type == VIR_DOMAIN_DEVICE_HOSTDEV &&
+        dev.data.hostdev->deleteCause == VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING) {
+        virDomainHostdevDefPtr hostdev = dev.data.hostdev;
+
+        if (qemuDomainRemoveHostDevice(driver, vm, hostdev) < 0)
+            return -1;
+
+        if (qemuDomainAttachHostDevice(driver, vm, hostdev) < 0)
+            return -1;
+
+        hostdev->deleteCause = 0;
+    } else {
+        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
+            return -1;
+    }
+
+    return 0;
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index bf812eab1a..f85e5db2fe 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -151,3 +151,7 @@ int qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                               virDomainDefPtr persistentDef,
                               virBitmapPtr vcpus,
                               bool state);
+
+int qemuDomainRemoveDeviceAlias(virQEMUDriverPtr driver,
+                                virDomainObjPtr vm,
+                                const char *devAlias);
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index d710193b94..a2c0c07eb9 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -1429,8 +1429,7 @@ virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
     }
 
  out:
-    if (!*usb)
-        hostdev->missing = true;
+    hostdev->missing = !*usb;
     return 0;
 }
 
@@ -1472,7 +1471,8 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr mgr,
 
         if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
             (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
-             !coldBoot))
+             !coldBoot) ||
+            hostdev->deleteCause == VIR_DOMAIN_HOSTDEV_DELETE_CAUSE_REATTACHING)
             required = false;
 
         if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
-- 
2.23.0




More information about the libvir-list mailing list