aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-10-13 17:18:02 -0400
committerTakashi Iwai <tiwai@suse.de>2014-10-14 03:18:02 -0400
commit95926035b187cc9fee6fb61385b7da9c28123f74 (patch)
tree06f381609dd013ede40038643916a0d5deade923 /sound
parent811deedebab38f8360a700a52b0b75688c9a10f7 (diff)
ALSA: emu10k1: Fix deadlock in synth voice lookup
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>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c6
1 files 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)
85 * get more voice for pcm 85 * get more voice for pcm
86 * 86 *
87 * terminate most inactive voice and give it as a pcm voice. 87 * terminate most inactive voice and give it as a pcm voice.
88 *
89 * voice_lock is already held.
88 */ 90 */
89int 91int
90snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) 92snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
@@ -92,12 +94,10 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
92 struct snd_emux *emu; 94 struct snd_emux *emu;
93 struct snd_emux_voice *vp; 95 struct snd_emux_voice *vp;
94 struct best_voice best[V_END]; 96 struct best_voice best[V_END];
95 unsigned long flags;
96 int i; 97 int i;
97 98
98 emu = hw->synth; 99 emu = hw->synth;
99 100
100 spin_lock_irqsave(&emu->voice_lock, flags);
101 lookup_voices(emu, hw, best, 1); /* no OFF voices */ 101 lookup_voices(emu, hw, best, 1); /* no OFF voices */
102 for (i = 0; i < V_END; i++) { 102 for (i = 0; i < V_END; i++) {
103 if (best[i].voice >= 0) { 103 if (best[i].voice >= 0) {
@@ -113,11 +113,9 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
113 vp->emu->num_voices--; 113 vp->emu->num_voices--;
114 vp->ch = -1; 114 vp->ch = -1;
115 vp->state = SNDRV_EMUX_ST_OFF; 115 vp->state = SNDRV_EMUX_ST_OFF;
116 spin_unlock_irqrestore(&emu->voice_lock, flags);
117 return ch; 116 return ch;
118 } 117 }
119 } 118 }
120 spin_unlock_irqrestore(&emu->voice_lock, flags);
121 119
122 /* not found */ 120 /* not found */
123 return -ENOMEM; 121 return -ENOMEM;