[RFC PATCH 2/2] ALSA: pcm: refresh capture pointers before drain

From: Joonho Lee

Date: Tue Oct 13 2026 - 23:33:21 EST


Refresh active capture pointers before the drain transition so the final
captured tail is accounted before reads finish.

Assisted-by: LLM
Signed-off-by: Joonho Lee <mynameisjune111@xxxxxxxxx>
---
sound/core/pcm_native.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index defbb2977efe..622ae7be2d04 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2176,14 +2176,32 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
} else if (substream->f_flags & O_NONBLOCK)
nonblock = 1;

- snd_pcm_stream_lock_irq(substream);
- /* resume pause */
- if (runtime->state == SNDRV_PCM_STATE_PAUSED)
- snd_pcm_pause(substream, false);
+ /* Keep linked runtimes alive until the initial drain action completes. */
+ scoped_guard(rwsem_read, &snd_pcm_link_rwsem) {
+ snd_pcm_stream_lock_irq(substream);
+ /* Resume before refreshing capture positions. */
+ if (runtime->state == SNDRV_PCM_STATE_PAUSED)
+ snd_pcm_pause(substream, false);
+ snd_pcm_stream_unlock_irq(substream);
+
+ /* A pointer error may stop the group: hold only this member's lock. */
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->stream != SNDRV_PCM_STREAM_CAPTURE)
+ continue;
+ scoped_guard(pcm_stream_lock_irq, s) {
+ if (s->runtime->state == SNDRV_PCM_STATE_RUNNING)
+ result = snd_pcm_update_hw_ptr(s);
+ }
+ if (result < 0)
+ break;
+ }

- /* pre-start/stop - all running streams are changed to DRAINING state */
- result = snd_pcm_action(&snd_pcm_action_drain_init, substream,
- ACTION_ARG_IGNORE);
+ snd_pcm_stream_lock_irq(substream);
+ /* Change the stable group to DRAINING only after all refreshes. */
+ if (result >= 0)
+ result = snd_pcm_action(&snd_pcm_action_drain_init,
+ substream, ACTION_ARG_IGNORE);
+ }
if (result < 0)
goto unlock;
/* in non-blocking, we don't wait in ioctl but let caller poll */