From a6a1f3005929d1a7ed35d683ba4ce2a12aad7395 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Feb 2016 11:53:30 +0100 Subject: [PATCH] ALSA: timer: Protect the whole snd_timer_close() with open race commit 9984d1b5835ca29fc7025186a891ee7398d21cc7 upstream. In order to make the open/close more robust, widen the register_mutex protection over the whole snd_timer_close() function. Also, the close procedure is slightly shuffled to be in the safer order, as well as a few code refactoring. Signed-off-by: Takashi Iwai [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings --- sound/core/timer.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/sound/core/timer.c b/sound/core/timer.c index 7754a37de7e9..80ca9586d9b0 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -326,25 +326,14 @@ int snd_timer_close(struct snd_timer_instance *timeri) if (snd_BUG_ON(!timeri)) return -ENXIO; + mutex_lock(®ister_mutex); + list_del(&timeri->open_list); + /* force to stop the timer */ snd_timer_stop(timeri); - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - /* wait, until the active callback is finished */ - spin_lock_irq(&slave_active_lock); - while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { - spin_unlock_irq(&slave_active_lock); - udelay(10); - spin_lock_irq(&slave_active_lock); - } - spin_unlock_irq(&slave_active_lock); - mutex_lock(®ister_mutex); - list_del(&timeri->open_list); - mutex_unlock(®ister_mutex); - } else { - timer = timeri->timer; - if (snd_BUG_ON(!timer)) - goto out; + timer = timeri->timer; + if (timer) { /* wait, until the active callback is finished */ spin_lock_irq(&timer->lock); while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { @@ -353,11 +342,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_lock_irq(&timer->lock); } spin_unlock_irq(&timer->lock); - mutex_lock(®ister_mutex); - list_del(&timeri->open_list); - if (list_empty(&timer->open_list_head) && - timer->hw.close) - timer->hw.close(timer); + /* remove slave links */ spin_lock_irq(&slave_active_lock); spin_lock(&timer->lock); @@ -371,15 +356,24 @@ int snd_timer_close(struct snd_timer_instance *timeri) } spin_unlock(&timer->lock); spin_unlock_irq(&slave_active_lock); - mutex_unlock(®ister_mutex); + + /* slave doesn't need to release timer resources below */ + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) + timer = NULL; } - out: + if (timeri->private_free) timeri->private_free(timeri); kfree(timeri->owner); kfree(timeri); - if (timer) + + if (timer) { + if (list_empty(&timer->open_list_head) && timer->hw.close) + timer->hw.close(timer); module_put(timer->module); + } + + mutex_unlock(®ister_mutex); return 0; } -- 2.39.2