mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 04:34:11 +08: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))
|
if (snd_BUG_ON(!timeri))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
mutex_lock(®ister_mutex);
|
||||||
|
list_del(&timeri->open_list);
|
||||||
|
|
||||||
/* force to stop the timer */
|
/* force to stop the timer */
|
||||||
snd_timer_stop(timeri);
|
snd_timer_stop(timeri);
|
||||||
|
|
||||||
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
|
timer = timeri->timer;
|
||||||
/* wait, until the active callback is finished */
|
if (timer) {
|
||||||
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;
|
|
||||||
/* wait, until the active callback is finished */
|
/* wait, until the active callback is finished */
|
||||||
spin_lock_irq(&timer->lock);
|
spin_lock_irq(&timer->lock);
|
||||||
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
|
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_lock_irq(&timer->lock);
|
||||||
}
|
}
|
||||||
spin_unlock_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 */
|
/* remove slave links */
|
||||||
spin_lock_irq(&slave_active_lock);
|
spin_lock_irq(&slave_active_lock);
|
||||||
spin_lock(&timer->lock);
|
spin_lock(&timer->lock);
|
||||||
@ -363,18 +348,27 @@ int snd_timer_close(struct snd_timer_instance *timeri)
|
|||||||
}
|
}
|
||||||
spin_unlock(&timer->lock);
|
spin_unlock(&timer->lock);
|
||||||
spin_unlock_irq(&slave_active_lock);
|
spin_unlock_irq(&slave_active_lock);
|
||||||
/* release a card refcount for safe disconnection */
|
|
||||||
if (timer->card)
|
/* slave doesn't need to release timer resources below */
|
||||||
put_device(&timer->card->card_dev);
|
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
|
||||||
mutex_unlock(®ister_mutex);
|
timer = NULL;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
if (timeri->private_free)
|
if (timeri->private_free)
|
||||||
timeri->private_free(timeri);
|
timeri->private_free(timeri);
|
||||||
kfree(timeri->owner);
|
kfree(timeri->owner);
|
||||||
kfree(timeri);
|
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);
|
module_put(timer->module);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(®ister_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user