From df55531b8b0eea9d2473f5697ae4f38d0df6bec7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Apr 2019 12:25:32 +0200 Subject: 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 --- sound/core/timer.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound/core') 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); } } -- cgit v1.2.3