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

Wen Congyang wency at cn.fujitsu.com
Wed Apr 6 07:13:14 UTC 2011


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




More information about the libvir-list mailing list