Skip to content

Commit a38440f

Browse files
tiwaigregkh
authored andcommitted
ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls
commit 3c3201f upstream. Like the previous fixes to hw_params and hw_free ioctl races, we need to paper over the concurrent prepare ioctl calls against hw_params and hw_free, too. This patch implements the locking with the existing runtime->buffer_mutex for prepare ioctls. Unlike the previous case for snd_pcm_hw_hw_params() and snd_pcm_hw_free(), snd_pcm_prepare() is performed to the linked streams, hence the lock can't be applied simply on the top. For tracking the lock in each linked substream, we modify snd_pcm_action_group() slightly and apply the buffer_mutex for the case stream_lock=false (formerly there was no lock applied) there. Cc: <stable@vger.kernel.org> Reviewed-by: Jaroslav Kysela <perex@perex.cz> Link: https://lore.kernel.org/r/20220322170720.3529-4-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 8527c8f commit a38440f

1 file changed

Lines changed: 18 additions & 14 deletions

File tree

sound/core/pcm_native.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,15 +1171,17 @@ struct action_ops {
11711171
static int snd_pcm_action_group(const struct action_ops *ops,
11721172
struct snd_pcm_substream *substream,
11731173
snd_pcm_state_t state,
1174-
bool do_lock)
1174+
bool stream_lock)
11751175
{
11761176
struct snd_pcm_substream *s = NULL;
11771177
struct snd_pcm_substream *s1;
11781178
int res = 0, depth = 1;
11791179

11801180
snd_pcm_group_for_each_entry(s, substream) {
1181-
if (do_lock && s != substream) {
1182-
if (s->pcm->nonatomic)
1181+
if (s != substream) {
1182+
if (!stream_lock)
1183+
mutex_lock_nested(&s->runtime->buffer_mutex, depth);
1184+
else if (s->pcm->nonatomic)
11831185
mutex_lock_nested(&s->self_group.mutex, depth);
11841186
else
11851187
spin_lock_nested(&s->self_group.lock, depth);
@@ -1207,18 +1209,18 @@ static int snd_pcm_action_group(const struct action_ops *ops,
12071209
ops->post_action(s, state);
12081210
}
12091211
_unlock:
1210-
if (do_lock) {
1211-
/* unlock streams */
1212-
snd_pcm_group_for_each_entry(s1, substream) {
1213-
if (s1 != substream) {
1214-
if (s1->pcm->nonatomic)
1215-
mutex_unlock(&s1->self_group.mutex);
1216-
else
1217-
spin_unlock(&s1->self_group.lock);
1218-
}
1219-
if (s1 == s) /* end */
1220-
break;
1212+
/* unlock streams */
1213+
snd_pcm_group_for_each_entry(s1, substream) {
1214+
if (s1 != substream) {
1215+
if (!stream_lock)
1216+
mutex_unlock(&s1->runtime->buffer_mutex);
1217+
else if (s1->pcm->nonatomic)
1218+
mutex_unlock(&s1->self_group.mutex);
1219+
else
1220+
spin_unlock(&s1->self_group.lock);
12211221
}
1222+
if (s1 == s) /* end */
1223+
break;
12221224
}
12231225
return res;
12241226
}
@@ -1348,10 +1350,12 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
13481350

13491351
/* Guarantee the group members won't change during non-atomic action */
13501352
down_read(&snd_pcm_link_rwsem);
1353+
mutex_lock(&substream->runtime->buffer_mutex);
13511354
if (snd_pcm_stream_linked(substream))
13521355
res = snd_pcm_action_group(ops, substream, state, false);
13531356
else
13541357
res = snd_pcm_action_single(ops, substream, state);
1358+
mutex_unlock(&substream->runtime->buffer_mutex);
13551359
up_read(&snd_pcm_link_rwsem);
13561360
return res;
13571361
}

0 commit comments

Comments
 (0)