]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: pcm: Serialize snd_pcm_suspend_all() with open_mutex
authorCássio Gabriel <cassiogabrielcontato@gmail.com>
Fri, 27 Mar 2026 13:59:45 +0000 (10:59 -0300)
committerTakashi Iwai <tiwai@suse.de>
Fri, 27 Mar 2026 14:12:28 +0000 (15:12 +0100)
snd_pcm_suspend_all() walks all PCM substreams and uses a lockless
runtime check to skip closed streams. It then calls snd_pcm_suspend()
for each remaining substream and finally runs snd_pcm_sync_stop() in a
second pass.

The runtime lifetime is still controlled by pcm->open_mutex in the
open/release path. That means a concurrent close can clear or free
substream->runtime after the initial check in snd_pcm_suspend_all(),
leaving the later suspend or sync-stop path to dereference a stale or
NULL runtime pointer.

Serialize snd_pcm_suspend_all() with pcm->open_mutex so the runtime
pointer stays stable across both loops. This matches the existing PCM
runtime lifetime rule already used by other core paths that access
substream->runtime outside the stream lock.

Suggested-by: Takashi Iwai <tiwai@suse.com>
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260327-alsa-pcm-suspend-open-close-lock-v2-1-cc4baca4dcd6@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/pcm_native.c

index 394f86bc4d2920d4c750249691628464d03e3134..aefb861ab873b95199bfb4d4238f0ed8ce1a51b0 100644 (file)
@@ -1780,6 +1780,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream)
  * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm
  * @pcm: the PCM instance
  *
+ * Takes and releases pcm->open_mutex to serialize against
+ * concurrent open/close while walking the substreams.
+ *
  * After this call, all streams are changed to SUSPENDED state.
  *
  * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
@@ -1792,8 +1795,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
        if (! pcm)
                return 0;
 
+       guard(mutex)(&pcm->open_mutex);
+
        for_each_pcm_substream(pcm, stream, substream) {
-               /* FIXME: the open/close code should lock this as well */
                if (!substream->runtime)
                        continue;