Message ID | 1476201.kR505WbUas@vostro.rjw.lan (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On Wed, Jan 15, 2014 at 02:36:36PM +0100, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > Subject: powerpc / eeh_driver: Use global PCI rescan-remove locking > > Race conditions are theoretically possible between the PCI device > addition and removal in the PPC64 PCI error recovery driver and > the generic PCI bus rescan and device removal that can be triggered > via sysfs. > > To avoid those race conditions make PPC64 PCI error recovery driver > use global PCI rescan-remove locking around PCI device addition and > removal. > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > --- > > The previous version had wrong function names in the last hunk, sorry about > that. I replaced the previous version and re-pushed the pci/locking branch, thanks! > > Rafael > > --- > arch/powerpc/kernel/eeh_driver.c | 19 ++++++++++++++++--- > 1 file changed, 16 insertions(+), 3 deletions(-) > > Index: linux-pm/arch/powerpc/kernel/eeh_driver.c > =================================================================== > --- linux-pm.orig/arch/powerpc/kernel/eeh_driver.c > +++ linux-pm/arch/powerpc/kernel/eeh_driver.c > @@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, > edev->mode |= EEH_DEV_DISCONNECTED; > (*removed)++; > > + pci_lock_rescan_remove(); > pci_stop_and_remove_bus_device(dev); > + pci_unlock_rescan_remove(); > > return NULL; > } > @@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_p > * into pcibios_add_pci_devices(). > */ > eeh_pe_state_mark(pe, EEH_PE_KEEP); > - if (bus) > + if (bus) { > + pci_lock_rescan_remove(); > pcibios_remove_pci_devices(bus); > - else if (frozen_bus) > + pci_unlock_rescan_remove(); > + } else if (frozen_bus) { > eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); > + } > > /* Reset the pci controller. (Asserts RST#; resets config space). > * Reconfigure bridges and devices. Don't try to bring the system > @@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_p > if (rc) > return rc; > > + pci_lock_rescan_remove(); > + > /* Restore PE */ > eeh_ops->configure_bridge(pe); > eeh_pe_restore_bars(pe); > @@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_p > pe->tstamp = tstamp; > pe->freeze_count = cnt; > > + pci_unlock_rescan_remove(); > return 0; > } > > @@ -618,8 +626,11 @@ perm_error: > eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); > > /* Shut down the device drivers for good. */ > - if (frozen_bus) > + if (frozen_bus) { > + pci_lock_rescan_remove(); > pcibios_remove_pci_devices(frozen_bus); > + pci_unlock_rescan_remove(); > + } > } > > static void eeh_handle_special_event(void) > @@ -692,6 +703,7 @@ static void eeh_handle_special_event(voi > if (rc == 2 || rc == 1) > eeh_handle_normal_event(pe); > else { > + pci_lock_rescan_remove(); > list_for_each_entry_safe(hose, tmp, > &hose_list, list_node) { > phb_pe = eeh_phb_pe_get(hose); > @@ -703,6 +715,7 @@ static void eeh_handle_special_event(voi > eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); > pcibios_remove_pci_devices(bus); > } > + pci_unlock_rescan_remove(); > } > } > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-pci" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Index: linux-pm/arch/powerpc/kernel/eeh_driver.c =================================================================== --- linux-pm.orig/arch/powerpc/kernel/eeh_driver.c +++ linux-pm/arch/powerpc/kernel/eeh_driver.c @@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, edev->mode |= EEH_DEV_DISCONNECTED; (*removed)++; + pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); + pci_unlock_rescan_remove(); return NULL; } @@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_p * into pcibios_add_pci_devices(). */ eeh_pe_state_mark(pe, EEH_PE_KEEP); - if (bus) + if (bus) { + pci_lock_rescan_remove(); pcibios_remove_pci_devices(bus); - else if (frozen_bus) + pci_unlock_rescan_remove(); + } else if (frozen_bus) { eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); + } /* Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system @@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_p if (rc) return rc; + pci_lock_rescan_remove(); + /* Restore PE */ eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); @@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_p pe->tstamp = tstamp; pe->freeze_count = cnt; + pci_unlock_rescan_remove(); return 0; } @@ -618,8 +626,11 @@ perm_error: eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); /* Shut down the device drivers for good. */ - if (frozen_bus) + if (frozen_bus) { + pci_lock_rescan_remove(); pcibios_remove_pci_devices(frozen_bus); + pci_unlock_rescan_remove(); + } } static void eeh_handle_special_event(void) @@ -692,6 +703,7 @@ static void eeh_handle_special_event(voi if (rc == 2 || rc == 1) eeh_handle_normal_event(pe); else { + pci_lock_rescan_remove(); list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { phb_pe = eeh_phb_pe_get(hose); @@ -703,6 +715,7 @@ static void eeh_handle_special_event(voi eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); pcibios_remove_pci_devices(bus); } + pci_unlock_rescan_remove(); } }