[Update,8/9] powerpc / eeh_driver: Use global PCI rescan-remove locking
diff mbox series

Message ID 1476201.kR505WbUas@vostro.rjw.lan
State New, archived
Headers show
Series
  • Untitled series #195089
Related show

Commit Message

Rafael J. Wysocki Jan. 15, 2014, 1:36 p.m. UTC
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.

Rafael

---
 arch/powerpc/kernel/eeh_driver.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Comments

Bjorn Helgaas Jan. 15, 2014, 5:38 p.m. UTC | #1
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-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Patch
diff mbox series

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();
 	}
 }