ALSA: emu10k1: Fix deadlock in synth voice lookup
commit 95926035b1
upstream.
The emu10k1 voice allocator takes voice_lock spinlock. When there is
no empty stream available, it tries to release a voice used by synth,
and calls get_synth_voice. The callback function,
snd_emu10k1_synth_get_voice(), however, also takes the voice_lock,
thus it deadlocks.
The fix is simply removing the voice_lock holds in
snd_emu10k1_synth_get_voice(), as this is always called in the
spinlock context.
Reported-and-tested-by: Arthur Marsh <arthur.marsh@internode.on.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
4f5de92148
commit
725a14505c
|
@ -85,6 +85,8 @@ snd_emu10k1_ops_setup(struct snd_emux *emux)
|
|||
* get more voice for pcm
|
||||
*
|
||||
* terminate most inactive voice and give it as a pcm voice.
|
||||
*
|
||||
* voice_lock is already held.
|
||||
*/
|
||||
int
|
||||
snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
|
||||
|
@ -92,12 +94,10 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
|
|||
struct snd_emux *emu;
|
||||
struct snd_emux_voice *vp;
|
||||
struct best_voice best[V_END];
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
emu = hw->synth;
|
||||
|
||||
spin_lock_irqsave(&emu->voice_lock, flags);
|
||||
lookup_voices(emu, hw, best, 1); /* no OFF voices */
|
||||
for (i = 0; i < V_END; i++) {
|
||||
if (best[i].voice >= 0) {
|
||||
|
@ -113,11 +113,9 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
|
|||
vp->emu->num_voices--;
|
||||
vp->ch = -1;
|
||||
vp->state = SNDRV_EMUX_ST_OFF;
|
||||
spin_unlock_irqrestore(&emu->voice_lock, flags);
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&emu->voice_lock, flags);
|
||||
|
||||
/* not found */
|
||||
return -ENOMEM;
|
||||
|
|
Loading…
Reference in New Issue