Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: usb: host: Fix deadlock in oxu_bus_suspend()

There is a deadlock in oxu_bus_suspend(), which is shown below:

(Thread 1) | (Thread 2)
| timer_action()
oxu_bus_suspend() | mod_timer()
spin_lock_irq() //(1) | (wait a time)
... | oxu_watchdog()
del_timer_sync() | spin_lock_irq() //(2)
(wait timer to stop) | ...

We hold oxu->lock in position (1) of thread 1, and use
del_timer_sync() to wait timer to stop, but timer handler
also need oxu->lock in position (2) of thread 2. As a result,
oxu_bus_suspend() will block forever.

This patch extracts del_timer_sync() from the protection of
spin_lock_irq(), which could let timer handler to obtain
the needed lock.

Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Link: https://lore.kernel.org/r/20220417120305.64577-1-duoming@zju.edu.cn
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Duoming Zhou and committed by
Greg Kroah-Hartman
4d378f2a bf594d1d

+2
+2
drivers/usb/host/oxu210hp-hcd.c
··· 3909 3909 } 3910 3910 } 3911 3911 3912 + spin_unlock_irq(&oxu->lock); 3912 3913 /* turn off now-idle HC */ 3913 3914 del_timer_sync(&oxu->watchdog); 3915 + spin_lock_irq(&oxu->lock); 3914 3916 ehci_halt(oxu); 3915 3917 hcd->state = HC_STATE_SUSPENDED; 3916 3918