summaryrefslogtreecommitdiffstats
path: root/sound/core/timer.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-04-09 12:25:32 +0200
committerTakashi Iwai <tiwai@suse.de>2019-04-09 12:29:34 +0200
commitdf55531b8b0eea9d2473f5697ae4f38d0df6bec7 (patch)
treea6fac1cad0346f2f2bec14c8e9682221070e856e /sound/core/timer.c
parent4b81dad109ad7d7b288804fcdc6475b48f242210 (diff)
downloadlinux-df55531b8b0eea9d2473f5697ae4f38d0df6bec7.tar.bz2
ALSA: timer: Revert active callback sync check at close
This is essentially a revert of the commit a7588c896b05 ("ALSA: timer: Check ack_list emptiness instead of bit flag"). The intended change by the commit turns out to be insufficient, as snd_timer_close*() always calls snd_timer_stop() that deletes the ack_list beforehand. In theory, we can change the behavior of snd_timer_stop() to sync the pending ack_list, but this will become a deadlock for the callback like sequencer that calls again snd_timer_stop() from itself. So, reverting the change is a more straightforward solution. Fixes: a7588c896b05 ("ALSA: timer: Check ack_list emptiness instead of bit flag") Reported-by: syzbot+58813d77154713f4de15@syzkaller.appspotmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r--sound/core/timer.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index bb7e90ab90f8..df52d2960179 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -372,7 +372,7 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri)
timer->num_instances--;
/* wait, until the active callback is finished */
spin_lock_irq(&timer->lock);
- while (!list_empty(&timeri->ack_list)) {
+ while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
spin_unlock_irq(&timer->lock);
udelay(10);
spin_lock_irq(&timer->lock);
@@ -748,19 +748,20 @@ static void snd_timer_process_callbacks(struct snd_timer *timer,
ti = list_first_entry(head, struct snd_timer_instance,
ack_list);
+ /* remove from ack_list and make empty */
+ list_del_init(&ti->ack_list);
+
if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
ticks = ti->pticks;
ti->pticks = 0;
resolution = ti->resolution;
-
+ ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
spin_unlock(&timer->lock);
if (ti->callback)
ti->callback(ti, resolution, ticks);
spin_lock(&timer->lock);
+ ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
}
-
- /* remove from ack_list and make empty */
- list_del_init(&ti->ack_list);
}
}