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 | 90 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/util/pci.c b/src/util/pci.c index 8d2dbb0..e30f5cf 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 { @@ -834,11 +839,25 @@ recheck: } +static int pciUnBindDeviceFromStub(pciDevice *dev, const char *driver); static int pciBindDeviceToStub(pciDevice *dev, const char *driver) { char drvdir[PATH_MAX]; char path[PATH_MAX]; + int reprobe = 0; + int ret = 0; + + /* check whether the device is already bound to a driver */ + pciDriverDir(drvdir, sizeof(drvdir), driver); + pciDeviceFile(path, sizeof(path), dev->name, "driver"); + if (virFileExists(path)) { + if (virFileLinkPointsTo(path, drvdir)) { + /* The device is already bound to pci-stub */ + return 0; + } + 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. @@ -856,16 +875,31 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) return -1; } + /* check whether the device is bound to pci-stub when we write dev->id to + * new_id. + */ + pciDriverDir(drvdir, sizeof(drvdir), driver); + pciDeviceFile(path, sizeof(path), dev->name, "driver"); + 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 * your root filesystem. */ pciDeviceFile(path, sizeof(path), dev->name, "driver/unbind"); - if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to unbind PCI device '%s'"), dev->name); - return -1; + if (virFileExists(path)) { + if (virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to unbind PCI device '%s'"), + dev->name); + return -1; + } + dev->reprobe = reprobe; } /* If the device isn't already bound to pci-stub, try binding it now. @@ -879,18 +913,23 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) virReportSystemError(errno, _("Failed to add slot for PCI device '%s' to %s"), dev->name, driver); - return -1; + ret = -1; + goto remove_id; } + dev->remove_slot = 1; pciDriverFile(path, sizeof(path), driver, "bind"); if (virFileWriteStr(path, dev->name, 0) < 0) { virReportSystemError(errno, _("Failed to bind PCI device '%s' to %s"), dev->name, driver); - return -1; + ret = -1; + 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. */ @@ -899,10 +938,21 @@ pciBindDeviceToStub(pciDevice *dev, const char *driver) virReportSystemError(errno, _("Failed to remove PCI ID '%s' from %s"), dev->id, driver); - return -1; + ret = -1; + + /* 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; } - return 0; + if (ret < 0) { + pciUnBindDeviceFromStub(dev, driver); + } + + return ret; } int @@ -930,6 +980,9 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) char drvdir[PATH_MAX]; char path[PATH_MAX]; + if (!dev->unbind_from_stub) + goto remove_slot; + /* If the device is bound to stub, unbind it. */ pciDriverDir(drvdir, sizeof(drvdir), driver); @@ -938,21 +991,36 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) pciDriverFile(path, sizeof(path), driver, "unbind"); 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); + /* do not do it again */ + dev->unbind_from_stub = 0; + dev->remove_slot = 0; + dev->reprobe = 0; return -1; } } + 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 */ pciDriverFile(path, sizeof(path), driver, "remove_slot"); 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); + dev->remove_slot = 0; + dev->reprobe = 0; return -1; } + dev->remove_slot = 0; +reprobe: + if (!dev->reprobe) + return 0; /* 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 @@ -965,9 +1033,11 @@ pciUnBindDeviceFromStub(pciDevice *dev, const char *driver) virReportSystemError(errno, _("Failed to trigger a re-probe for PCI device '%s'"), dev->name); + dev->reprobe = 0; return -1; } } + dev->reprobe = 0; return 0; } -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list