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