summaryrefslogtreecommitdiff
path: root/drivers/pci/hotplug/pciehp.h
diff options
context:
space:
mode:
authorYijing Wang <wangyijing@huawei.com>2013-01-11 10:15:54 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-27 20:47:43 -0800
commit5f3e5a32d083008c1ad850375d24fc85a27803e4 (patch)
tree4d440fea7cac28d605b81e3fcd934f56a8929813 /drivers/pci/hotplug/pciehp.h
parent11cfb2b163f483a4c97e5a229635d0f6b23bd5ac (diff)
PCI: pciehp: Use per-slot workqueues to avoid deadlock
commit c2be6f93b383c873a4f9d521afa49b1b67d06085 upstream. When we have a hotplug-capable PCIe port with a second hotplug-capable PCIe port below it, removing the device below the upstream port causes a deadlock. The deadlock happens because we use the pciehp_wq workqueue to run pciehp_power_thread(), which uses pciehp_disable_slot() to remove devices below the upstream port. When we remove the downstream PCIe port, we call pciehp_remove(), the pciehp driver's .remove() method. That calls flush_workqueue(pciehp_wq), which deadlocks because the pciehp_power_thread() work item is still running. This patch avoids the deadlock by creating a workqueue for every PCIe port and removing the single shared workqueue. Here's the call path that leads to the deadlock: pciehp_queue_pushbutton_work queue_work(pciehp_wq) # queue pciehp_power_thread ... pciehp_power_thread pciehp_disable_slot remove_board pciehp_unconfigure_device pci_stop_and_remove_bus_device ... pciehp_remove # pciehp driver .remove method pciehp_release_ctrl pcie_cleanup_slot flush_workqueue(pciehp_wq) This is fairly urgent because it can be caused by simply unplugging a Thunderbolt adapter, as reported by Daniel below. [bhelgaas: changelog] Reference: http://lkml.kernel.org/r/CAMVG2ssiRgcTD1bej2tkUUfsWmpL5eNtPcNif9va2-Gzb2u8nQ@mail.gmail.com Reported-and-tested-by: Daniel J Blueman <daniel@quora.org> Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pci/hotplug/pciehp.h')
-rw-r--r--drivers/pci/hotplug/pciehp.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4b7cce1de6ec..a321b77a5e82 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,7 +44,6 @@ extern bool pciehp_poll_mode;
extern int pciehp_poll_time;
extern bool pciehp_debug;
extern bool pciehp_force;
-extern struct workqueue_struct *pciehp_wq;
#define dbg(format, arg...) \
do { \
@@ -78,6 +77,7 @@ struct slot {
struct hotplug_slot *hotplug_slot;
struct delayed_work work; /* work for button event */
struct mutex lock;
+ struct workqueue_struct *wq;
};
struct event_info {