Skip to content

Commit 7a58b8d

Browse files
stonezdmgregkh
authored andcommitted
usb: chipidea: fix deadlock in ci_otg_del_timer
There is a deadlock in ci_otg_del_timer(), the process is shown below: (thread 1) | (thread 2) ci_otg_del_timer() | ci_otg_hrtimer_func() ... | spin_lock_irqsave() //(1) | ... ... | hrtimer_cancel() | spin_lock_irqsave() //(2) (block forever) We hold ci->lock in position (1) and use hrtimer_cancel() to wait ci_otg_hrtimer_func() to stop, but ci_otg_hrtimer_func() also need ci->lock in position (2). As a result, the hrtimer_cancel() in ci_otg_del_timer() will be blocked forever. This patch extracts hrtimer_cancel() from the protection of spin_lock_irqsave() in order that the ci_otg_hrtimer_func() could obtain the ci->lock. What`s more, there will be no race happen. Because the "next_timer" is always under the protection of spin_lock_irqsave() and we only check whether "next_timer" equals to NUM_OTG_FSM_TIMERS in the following code. Fixes: 3a316ec ("usb: chipidea: use hrtimer for otg fsm timers") Cc: stable <[email protected]> Signed-off-by: Duoming Zhou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d68cc25 commit 7a58b8d

File tree

1 file changed

+2
-0
lines changed

1 file changed

+2
-0
lines changed

drivers/usb/chipidea/otg_fsm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,10 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum otg_fsm_timer t)
256256
ci->enabled_otg_timer_bits &= ~(1 << t);
257257
if (ci->next_otg_timer == t) {
258258
if (ci->enabled_otg_timer_bits == 0) {
259+
spin_unlock_irqrestore(&ci->lock, flags);
259260
/* No enabled timers after delete it */
260261
hrtimer_cancel(&ci->otg_fsm_hrtimer);
262+
spin_lock_irqsave(&ci->lock, flags);
261263
ci->next_otg_timer = NUM_OTG_FSM_TIMERS;
262264
} else {
263265
/* Find the next timer */

0 commit comments

Comments
 (0)