diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-10-13 17:18:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-10-14 03:18:02 -0400 |
commit | 95926035b187cc9fee6fb61385b7da9c28123f74 (patch) | |
tree | 06f381609dd013ede40038643916a0d5deade923 /sound | |
parent | 811deedebab38f8360a700a52b0b75688c9a10f7 (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.c | 6 |
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 | */ |
89 | int | 91 | int |
90 | snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) | 92 | snd_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; |