Message ID | 20230629121947.59315-1-dg573847474@gmail.com |
---|---|
State | New |
Headers | show |
Series | usb: host: oxu210hp-hcd: Fix potential deadlock on &oxu->mem_lock | expand |
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index f998d3f1a78a..944011e059e5 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1120,8 +1120,9 @@ static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu) { int i; struct oxu_murb *murb = NULL; + unsigned long flags; - spin_lock(&oxu->mem_lock); + spin_lock_irqsave(&oxu->mem_lock, flags); for (i = 0; i < MURB_NUM; i++) if (!oxu->murb_used[i]) @@ -1133,7 +1134,7 @@ static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu) oxu->murb_used[i] = 1; } - spin_unlock(&oxu->mem_lock); + spin_unlock_irqrestore(&oxu->mem_lock, flags); return murb; }
As &udc->lock is acquired by watchdog timer oxu_watchdog() under softirq context, other acquisition of the same lock under process context should disable irq, otherwise deadlock could happen if the irq preempt the execution while the lock is held in process context on the same CPU. The .urb_enqueue callback oxu_urb_enqueue() acquires the lock without disabling irq inside the function. Possible deadlock scenario oxu_urb_enqueue() -> oxu_murb_alloc() -> spin_lock(&oxu->mem_lock) <timer interrupt> -> oxu_watchdog() -> ehci_work() -> scan_async() -> qh_completions() -> oxu_murb_free() -> spin_lock(&oxu->mem_lock) This flaw was found by an experimental static analysis tool I am developing for irq-related deadlock, which reported the above warning when analyzing the linux kernel 6.4-rc7 release. The tentative patch fixes the potential deadlock by spin_lock_irqsave(). x86_64 allyesconfig using GCC shows no new warning, the tool does not report the warnining after the fix. No runtime testing was performed since I don't have device with OXU210HP host controller. Signed-off-by: Chengfeng Ye <dg573847474@gmail.com> --- drivers/usb/host/oxu210hp-hcd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)