mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
ALSA: timer: Protect the whole snd_timer_close() with open race
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 <tiwai@suse.de>
This commit is contained in:
parent
4dff5c7b70
commit
9984d1b583
@ -318,25 +318,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) {
|
||||
@ -345,11 +334,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);
|
||||
@ -363,18 +348,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
Block a user