Skip to content

Commit db9ae8f

Browse files
gatzkaStefan Richter
authored andcommitted
firewire: ohci: Fix deadlock at bus reset
Put bus_reset_work into its own workqueue. By doing this, forward progress of bus_reset_work() is guaranteed if the work is switched over to a rescuer thread. Switching work to a rescuer thread happens if a new worker thread could not be allocated in certain time (MAYDAY_INITIAL_TIMEOUT, typically 10 ms). This might not be possible under high memory pressure or even on a heavily loaded embedded system running a slow serial console. The former deadlock occured in the following situation: The rescuer thread ran fw_device_init->read_config_rom->read_rom->fw_run_transaction. fw_run_transaction blocked waiting for the completion object. This completion object would have been completed in bus_reset_work, but this work was never executed in the rescuer thread due to its strictly sequential behaviour. [Stefan R.: Removed WQ_NON_REENTRANT flag from allocation because it is no longer needed in current kernels. Add it back if you backport to kernels older than 3.7, i.e. one which does not contain dbf2576 "workqueue: make all workqueues non-reentrant". Swapped order of destroy_workqueue and pci_unregister_driver.] Signed-off-by: Stephan Gatzka <stephan.gatzka@gmail.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
1 parent 7a723c6 commit db9ae8f

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

drivers/firewire/ohci.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ struct fw_ohci {
242242
u32 self_id_buffer[512];
243243
};
244244

245+
static struct workqueue_struct *selfid_workqueue;
246+
245247
static inline struct fw_ohci *fw_ohci(struct fw_card *card)
246248
{
247249
return container_of(card, struct fw_ohci, card);
@@ -2087,7 +2089,7 @@ static irqreturn_t irq_handler(int irq, void *data)
20872089
log_irqs(ohci, event);
20882090

20892091
if (event & OHCI1394_selfIDComplete)
2090-
queue_work(fw_workqueue, &ohci->bus_reset_work);
2092+
queue_work(selfid_workqueue, &ohci->bus_reset_work);
20912093

20922094
if (event & OHCI1394_RQPkt)
20932095
tasklet_schedule(&ohci->ar_request_ctx.tasklet);
@@ -3872,12 +3874,17 @@ static struct pci_driver fw_ohci_pci_driver = {
38723874

38733875
static int __init fw_ohci_init(void)
38743876
{
3877+
selfid_workqueue = alloc_workqueue(KBUILD_MODNAME, WQ_MEM_RECLAIM, 0);
3878+
if (!selfid_workqueue)
3879+
return -ENOMEM;
3880+
38753881
return pci_register_driver(&fw_ohci_pci_driver);
38763882
}
38773883

38783884
static void __exit fw_ohci_cleanup(void)
38793885
{
38803886
pci_unregister_driver(&fw_ohci_pci_driver);
3887+
destroy_workqueue(selfid_workqueue);
38813888
}
38823889

38833890
module_init(fw_ohci_init);

0 commit comments

Comments
 (0)