[alsa-devel] [PATCH 1/2] ALSA: pcm: Fix referred substream in snd_pcm_action_group() unlock loop
In the unlock loop of snd_pcm_action_group(), the object "s" is used as the check of nonatomic PCM, but it should be rather "s1", which is the iterator of the loop. This supposedly causes a kernel panic when the substreams in operatino are linked.
Fixes: 257f8cce5d40 ('ALSA: pcm: Allow nonatomic trigger operations') Reported-and-tested-by: Arthur Marsh arthur.marsh@internode.on.net Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/pcm_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 85fe1a216225..bfe1cf6b492f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -818,7 +818,7 @@ static int snd_pcm_action_group(struct action_ops *ops, /* unlock streams */ snd_pcm_group_for_each_entry(s1, substream) { if (s1 != substream) { - if (s->pcm->nonatomic) + if (s1->pcm->nonatomic) mutex_unlock(&s1->self_group.mutex); else spin_unlock(&s1->self_group.lock);
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 Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/emu10k1/emu10k1_callback.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 3f3ef38d9b6e..874cd76c7b7f 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -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;
participants (1)
-
Takashi Iwai