[PATCH 2_2/3] reattach pci device when pciBindDeviceToStub() failed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We should bind pci device to original driver when pciBindDeviceToStub() failed.
If the pci device is not bound to any driver before calling pciBindDeviceToStub(),
we should only unbind it from pci-stub. If it is bound to pci-stub, we should not
unbid it from pci-stub.

---
 src/util/pci.c |  103 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/src/util/pci.c b/src/util/pci.c
index e69813c..ec9a0b9 100644
--- a/src/util/pci.c
+++ b/src/util/pci.c
@@ -65,6 +65,11 @@ struct _pciDevice {
     unsigned      has_flr : 1;
     unsigned      has_pm_reset : 1;
     unsigned      managed : 1;
+
+    /* used by reattach function */
+    unsigned      unbind_from_stub : 1;
+    unsigned      remove_slot : 1;
+    unsigned      reprobe : 1;
 };
 
 struct _pciDeviceList {
@@ -874,6 +879,9 @@ pciUnbindDeviceFromStub(pciDevice *dev, const char *driver)
     char *drvdir = NULL;
     char *path = NULL;
 
+    if (!dev->unbind_from_stub)
+        goto remove_slot;
+
     /* If the device is bound to stub, unbind it.
      */
     if (pciDriverDir(&drvdir, driver) < 0 ||
@@ -888,11 +896,16 @@ pciUnbindDeviceFromStub(pciDevice *dev, const char *driver)
 
         if (virFileWriteStr(path, dev->name, 0) < 0) {
             virReportSystemError(errno,
-                                 _("Failed to bind PCI device '%s' to %s"),
+                                 _("Failed to unbind PCI device '%s' from %s"),
                                  dev->name, driver);
             goto cleanup;
         }
     }
+    dev->unbind_from_stub = 0;
+
+remove_slot:
+    if (!dev->remove_slot)
+        goto reprobe;
 
     /* Xen's pciback.ko wants you to use remove_slot on the specific device */
     if (pciDriverFile(&path, driver, "remove_slot") < 0) {
@@ -901,10 +914,17 @@ pciUnbindDeviceFromStub(pciDevice *dev, const char *driver)
 
     if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
         virReportSystemError(errno,
-                             _("Failed to remove slot for PCI device '%s' to %s"),
+                             _("Failed to remove slot for PCI device '%s' from %s"),
                              dev->name, driver);
         goto cleanup;
     }
+    dev->remove_slot = 0;
+
+reprobe:
+    if (!dev->reprobe) {
+        result = 0;
+        goto cleanup;
+    }
 
     /* Trigger a re-probe of the device is not in the stub's dynamic
      * ID table. If the stub is available, but 'remove_id' isn't
@@ -927,6 +947,11 @@ pciUnbindDeviceFromStub(pciDevice *dev, const char *driver)
     result = 0;
 
 cleanup:
+    /* do not do it again */
+    dev->unbind_from_stub = 0;
+    dev->remove_slot = 0;
+    dev->reprobe = 0;
+
     VIR_FREE(drvdir);
     VIR_FREE(path);
 
@@ -940,6 +965,22 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver)
     int result = -1;
     char *drvdir = NULL;
     char *path = NULL;
+    int reprobe = 0;
+
+    /* check whether the device is already bound to a driver */
+    if (pciDriverDir(&drvdir, driver) < 0 ||
+        pciDeviceFile(&path, dev->name, "driver") < 0) {
+        goto cleanup;
+    }
+
+    if (virFileExists(path)) {
+        if (virFileLinkPointsTo(path, drvdir)) {
+            /* The device is already bound to pci-stub */
+            result = 0;
+            goto cleanup;
+        }
+        reprobe = 1;
+    }
 
     /* Add the PCI device ID to the stub's dynamic ID table;
      * this is needed to allow us to bind the device to the stub.
@@ -950,7 +991,7 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver)
      * bound by the stub.
      */
     if (pciDriverFile(&path, driver, "new_id") < 0) {
-        return -1;
+        goto cleanup;
     }
 
     if (virFileWriteStr(path, dev->id, 0) < 0) {
@@ -960,6 +1001,20 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver)
         goto cleanup;
     }
 
+    /* check whether the device is bound to pci-stub when we write dev->id to
+     * new_id.
+     */
+    if (pciDriverDir(&drvdir, driver) < 0 ||
+        pciDeviceFile(&path, dev->name, "driver") < 0) {
+        goto remove_id;
+    }
+
+    if (virFileLinkPointsTo(path, drvdir)) {
+        dev->unbind_from_stub = 1;
+        dev->remove_slot = 1;
+        goto remove_id;
+    }
+
     /* If the device is already bound to a driver, unbind it.
      * Note, this will have rather unpleasant side effects if this
      * PCI device happens to be IDE controller for the disk hosting
@@ -969,48 +1024,61 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver)
         goto cleanup;
     }
 
-    if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
-        virReportSystemError(errno,
-                             _("Failed to unbind PCI device '%s'"), dev->name);
-        goto cleanup;
+    if (virFileExists(path)) {
+        if (virFileWriteStr(path, dev->name, 0) < 0) {
+            virReportSystemError(errno,
+                                 _("Failed to unbind PCI device '%s'"),
+                                 dev->name);
+            goto cleanup;
+        }
+        dev->reprobe = reprobe;
     }
 
     /* If the device isn't already bound to pci-stub, try binding it now.
      */
     if (pciDriverDir(&drvdir, driver) < 0 ||
         pciDeviceFile(&path, dev->name, "driver") < 0) {
-        goto cleanup;
+        goto remove_id;
     }
 
     if (!virFileLinkPointsTo(path, drvdir)) {
         /* Xen's pciback.ko wants you to use new_slot first */
         if (pciDriverFile(&path, driver, "new_slot") < 0) {
-            goto cleanup;
+            goto remove_id;
         }
 
         if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
             virReportSystemError(errno,
                                  _("Failed to add slot for PCI device '%s' to %s"),
                                  dev->name, driver);
-            goto cleanup;
+            goto remove_id;
         }
+        dev->remove_slot = 1;
 
         if (pciDriverFile(&path, driver, "bind") < 0) {
-            goto cleanup;
+            goto remove_id;
         }
 
         if (virFileWriteStr(path, dev->name, 0) < 0) {
             virReportSystemError(errno,
                                  _("Failed to bind PCI device '%s' to %s"),
                                  dev->name, driver);
-            goto cleanup;
+            goto remove_id;
         }
+        dev->unbind_from_stub = 1;
     }
 
+remove_id:
     /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
      * ID table so that 'drivers_probe' works below.
      */
     if (pciDriverFile(&path, driver, "remove_id") < 0) {
+        /* We do not remove PCI ID from pci-stub, and we can not reprobe it */
+        if (dev->reprobe) {
+            VIR_WARN("Not remove PCI ID '%s' from %s, and the device can"
+                     "not be reprobed again.", dev->id, driver);
+        }
+        dev->reprobe = 0;
         goto cleanup;
     }
 
@@ -1018,6 +1086,13 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver)
         virReportSystemError(errno,
                              _("Failed to remove PCI ID '%s' from %s"),
                              dev->id, driver);
+
+        /* remove PCI ID from pci-stub failed, and we can not reprobe it */
+        if (dev->reprobe) {
+            VIR_WARN("Faile to remove PCI ID '%s' from %s, and the device can"
+                     "not be reprobed again.", dev->id, driver);
+        }
+        dev->reprobe = 0;
         goto cleanup;
     }
 
@@ -1027,6 +1102,10 @@ cleanup:
     VIR_FREE(drvdir);
     VIR_FREE(path);
 
+    if (result < 0) {
+        pciUnbindDeviceFromStub(dev, driver);
+    }
+
     return result;
 }
 
-- 
1.7.1

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]