Commit fcfdebe70759c74e2e701f69aaa7f0e5e32cf5a6
1 parent
5f60e49608
Exists in
master
and in
7 other branches
ALSA: hrtimer - Fix lock-up
The timer stop callback can be called from snd_timer_interrupt(), which is called from the hrtimer callback. Since hrtimer_cancel() waits for the callback completion, this eventually results in a lock-up. This patch fixes the problem by just toggling a flag at stop callback and call hrtimer_cancel() later. Reported-and-tested-by: Wojtek Zabolotny <W.Zabolotny@elka.pw.edu.pl> Cc: <stable@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 1 changed file with 13 additions and 2 deletions Side-by-side Diff
sound/core/hrtimer.c
... | ... | @@ -37,14 +37,22 @@ |
37 | 37 | struct snd_hrtimer { |
38 | 38 | struct snd_timer *timer; |
39 | 39 | struct hrtimer hrt; |
40 | + atomic_t running; | |
40 | 41 | }; |
41 | 42 | |
42 | 43 | static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) |
43 | 44 | { |
44 | 45 | struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); |
45 | 46 | struct snd_timer *t = stime->timer; |
47 | + | |
48 | + if (!atomic_read(&stime->running)) | |
49 | + return HRTIMER_NORESTART; | |
50 | + | |
46 | 51 | hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); |
47 | 52 | snd_timer_interrupt(stime->timer, t->sticks); |
53 | + | |
54 | + if (!atomic_read(&stime->running)) | |
55 | + return HRTIMER_NORESTART; | |
48 | 56 | return HRTIMER_RESTART; |
49 | 57 | } |
50 | 58 | |
... | ... | @@ -58,6 +66,7 @@ |
58 | 66 | hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
59 | 67 | stime->timer = t; |
60 | 68 | stime->hrt.function = snd_hrtimer_callback; |
69 | + atomic_set(&stime->running, 0); | |
61 | 70 | t->private_data = stime; |
62 | 71 | return 0; |
63 | 72 | } |
64 | 73 | |
65 | 74 | |
... | ... | @@ -78,16 +87,18 @@ |
78 | 87 | { |
79 | 88 | struct snd_hrtimer *stime = t->private_data; |
80 | 89 | |
90 | + atomic_set(&stime->running, 0); | |
91 | + hrtimer_cancel(&stime->hrt); | |
81 | 92 | hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), |
82 | 93 | HRTIMER_MODE_REL); |
94 | + atomic_set(&stime->running, 1); | |
83 | 95 | return 0; |
84 | 96 | } |
85 | 97 | |
86 | 98 | static int snd_hrtimer_stop(struct snd_timer *t) |
87 | 99 | { |
88 | 100 | struct snd_hrtimer *stime = t->private_data; |
89 | - | |
90 | - hrtimer_cancel(&stime->hrt); | |
101 | + atomic_set(&stime->running, 0); | |
91 | 102 | return 0; |
92 | 103 | } |
93 | 104 |