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. Change-Id: I91f84b4eacddaf3347ec79ee81190021e3612dae Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
This commit is contained in:
parent
85a9ae72d3
commit
dce5a436fc
|
@ -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,18 +356,27 @@ int snd_timer_close(struct snd_timer_instance *timeri)
|
|||
}
|
||||
spin_unlock(&timer->lock);
|
||||
spin_unlock_irq(&slave_active_lock);
|
||||
/* release a card refcount for safe disconnection */
|
||||
if (timer->card)
|
||||
put_device(timer->card->card_dev);
|
||||
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);
|
||||
/* release a card refcount for safe disconnection */
|
||||
if (timer->card)
|
||||
put_device(timer->card->card_dev);
|
||||
module_put(timer->module);
|
||||
}
|
||||
|
||||
mutex_unlock(®ister_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue