From: sashiko-bot@kernel.org
To: "Joonho Lee" <mynameisjune111@gmail.com>, linux-sound@vger.kernel.org
Cc: virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH v8 08/14] ALSA: pcm: stop paused streams before synchronizing teardown
Date: Thu, 29 Oct 2026 06:04:46 +0000 [thread overview]
Message-ID: <sashiko-outbox-188788@kernel.org> (raw)
In-Reply-To: <20261029054354.2931-9-mynameisjune111@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] ALSA: pcm: unbalanced STOP trigger from PAUSED in snd_pcm_do_stop()
--
commit 1209424a81e0273da5db98a8f56a0fd0d7015011
Author: Joonho Lee <mynameisjune111@gmail.com>
ALSA: pcm: stop paused streams before synchronizing teardown
This commit updates snd_pcm_do_stop() to issue the SNDRV_PCM_TRIGGER_STOP
trigger and set stop_operating when a substream is in SNDRV_PCM_STATE_PAUSED,
in addition to when it is running.
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index a2ea44c3c1d29..2b18c5f5801f9 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -1607,7 +1607,8 @@ static int snd_pcm_do_stop(struct snd_pcm_substream *substream,
> snd_pcm_state_t state)
> {
> if (substream->runtime->trigger_master == substream &&
> - snd_pcm_running(substream)) {
> + (snd_pcm_running(substream) ||
> + substream->runtime->state == SNDRV_PCM_STATE_PAUSED)) {
> substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
> substream->runtime->stop_operating = true;
> }
[Severity: High]
Can calling substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP)
directly while in SNDRV_PCM_STATE_PAUSED cause regressions in drivers that
expect start-class triggers (START, RESUME, PAUSE_RELEASE) and stop-class
triggers (STOP, SUSPEND, PAUSE_PUSH) to be strictly paired?
When a substream enters SNDRV_PCM_STATE_PAUSED via snd_pcm_do_pause(), the
driver has already received SNDRV_PCM_TRIGGER_PAUSE_PUSH. Reaching
snd_pcm_do_stop() while runtime->state is still SNDRV_PCM_STATE_PAUSED
delivers SNDRV_PCM_TRIGGER_STOP without an intervening
SNDRV_PCM_TRIGGER_PAUSE_RELEASE.
This path can be reached from userspace when:
1. __snd_pcm_xrun() -> snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN) runs on
a paused stream without calling snd_pcm_pause(substream, false), such as
when ops->ack() returns -EPIPE in pcm_lib_apply_appl_ptr() during write,
read, rewind, forward, or SNDRV_PCM_IOCTL_SYNC_PTR, when avail reaches
runtime->stop_threshold in snd_pcm_update_state(), or via a direct driver
snd_pcm_stop() call.
2. snd_pcm_pause(substream, false) in snd_pcm_drop() or snd_pcm_prepare()
fails (its return value is ignored), for example if the driver's
SNDRV_PCM_TRIGGER_PAUSE_RELEASE trigger returns an error or if a linked
substream is not in SNDRV_PCM_STATE_PAUSED so snd_pcm_pre_pause() returns
-EBADFD.
3. snd_pcm_drop(), snd_pcm_prepare(), or snd_pcm_stop() is called on a
non-paused substream that is linked to a paused substream.
Several in-tree drivers appear to rely on never receiving
SNDRV_PCM_TRIGGER_STOP after SNDRV_PCM_TRIGGER_PAUSE_PUSH without an
intervening release:
1. Clock enable_count underflow in sound/soc/qcom/lpass-cpu.c
(lpass_cpu_daiops_trigger()) and sound/soc/spear/spdif_in.c
(spdif_in_trigger()):
sound/soc/qcom/lpass-cpu.c:lpass_cpu_daiops_trigger() {
...
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
...
clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
break;
}
Receiving STOP while PAUSED calls clk_disable() a second time for a single
clk_enable().
2. Runtime PM usage count underflow in sound/soc/samsung/i2s.c
(i2s_trigger()):
sound/soc/samsung/i2s.c:i2s_trigger() {
...
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
...
pm_runtime_put(dai->dev);
break;
}
Receiving STOP after PAUSE_PUSH calls pm_runtime_put(dai->dev) twice.
3. Reference and active counter underflows or premature shared hardware
shutdown in sound/soc/stm/stm32_i2s.c (stm32_i2s_trigger() decrementing
i2s->refcount), sound/soc/rockchip/rockchip_i2s_tdm.c
(rockchip_snd_txrxctrl() decrementing i2s_tdm->refcount),
sound/soc/atmel/atmel-i2s.c (atmel_i2s_trigger() decrementing
dev->clk_use_no), sound/soc/dwc/dwc-i2s.c (dw_i2s_trigger() decrementing
dev->active), sound/soc/ti/omap-mcbsp.c (omap_mcbsp_dai_trigger()
decrementing mcbsp->active), sound/soc/pxa/mmp-sspa.c
(mmp_sspa_trigger()), sound/soc/bcm/cygnus-ssp.c (cygnus_ssp_trigger()),
and sound/soc/fsl/imx-pcm-fiq.c (snd_imx_pcm_trigger() calling
disable_fiq(imx_pcm_fiq) twice):
sound/soc/stm/stm32_i2s.c:stm32_i2s_trigger() {
...
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
...
scoped_guard(spinlock, &i2s->lock_fd) {
i2s->refcount--;
}
4. SOF IPC4 pipeline state leak in sound/soc/sof/ipc4-pcm.c:
sound/soc/sof/ipc4-pcm.c:sof_ipc4_add_pipeline_to_trigger_list() {
...
case SOF_IPC4_PIPE_RESET:
/* RESET if the pipeline is neither running nor paused */
if (!spipe->started_count && !spipe->paused_count)
sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority,
true);
break;
case SOF_IPC4_PIPE_PAUSED:
case SOF_IPC4_PIPE_EOS:
if (spipe->paused_count == (spipe->started_count - 1))
sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority,
true);
break;
}
When START is followed by PAUSE_PUSH, spipe->started_count is 1 and
spipe->paused_count is 1. If SNDRV_PCM_TRIGGER_STOP is then issued while
PAUSED, sof_ipc4_pcm_trigger() requests SOF_IPC4_PIPE_PAUSED, the check
spipe->paused_count == (spipe->started_count - 1) evaluates to false, and
neither started_count nor paused_count is decremented (and
sof_ipc4_update_pipeline_state() only decrements paused_count on
SNDRV_PCM_TRIGGER_PAUSE_RELEASE). Subsequent sof_ipc4_pcm_hw_free() then
skips SOF_IPC4_PIPE_RESET because started_count and paused_count remain
non-zero.
5. Stuck hardware pause bits in sound/pci/cmipci.c (snd_cmipci_pcm_trigger()),
sound/pci/oxygen/oxygen_pcm.c (oxygen_trigger()), sound/pci/als300.c
(snd_als300_trigger()), sound/pci/ens1370.c (snd_ensoniq_trigger()), and
sound/pci/ice1712/ice1712.c (snd_ice1712_pcm_trigger()):
sound/pci/cmipci.c:snd_cmipci_pcm_trigger() {
...
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
cm->ctrl |= pause;
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
cm->ctrl &= ~pause;
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
break;
}
In these drivers, the pause bit is only cleared on PAUSE_RELEASE or RESUME,
not by SNDRV_PCM_TRIGGER_STOP or prepare().
6. Duplicate VIRTIO_SND_R_PCM_STOP in sound/virtio/virtio_pcm_ops.c
(virtsnd_pcm_trigger()):
sound/virtio/virtio_pcm_ops.c:virtsnd_pcm_trigger() {
...
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
scoped_guard(spinlock_irqsave, &vss->lock) {
if (command != SNDRV_PCM_TRIGGER_PAUSE_PUSH)
vss->stopped = true;
vss->xfer_enabled = false;
}
msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP,
GFP_KERNEL);
if (!msg)
return -ENOMEM;
return virtsnd_ctl_msg_send_sync(snd, msg);
}
Because SNDRV_PCM_TRIGGER_PAUSE_PUSH already sends VIRTIO_SND_R_PCM_STOP
to the device, triggering SNDRV_PCM_TRIGGER_STOP from
SNDRV_PCM_STATE_PAUSED sends a second VIRTIO_SND_R_PCM_STOP while the
device stream is already stopped.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261029054354.2931-1-mynameisjune111@gmail.com?part=8
next prev parent reply other threads:[~2026-10-29 6:04 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 5:43 [PATCH v8 00/14] ALSA: virtio: staged capture recovery and PCM RESET synchronization Joonho Lee
2026-10-29 5:43 ` [PATCH v8 01/14] ALSA: virtio: Propagate PCM send failures through ACK Joonho Lee
2026-10-29 6:06 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 02/14] ALSA: virtio: Recover PCM state after a failed start Joonho Lee
2026-10-29 6:10 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 03/14] ALSA: virtio: Retain queued messages through device reset Joonho Lee
2026-10-29 6:14 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 04/14] ALSA: virtio: Keep PCM DMA buffers alive through device ownership Joonho Lee
2026-10-29 6:07 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 05/14] ALSA: virtio: Keep control payloads alive through DMA completion Joonho Lee
2026-10-29 5:54 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 06/14] ALSA: virtio: wait through signals for PCM teardown Joonho Lee
2026-10-29 6:00 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 07/14] ALSA: pcm: mark stop-threshold accesses for capture policy sampling Joonho Lee
2026-10-29 5:48 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 08/14] ALSA: pcm: stop paused streams before synchronizing teardown Joonho Lee
2026-10-29 6:04 ` sashiko-bot [this message]
2026-10-29 5:43 ` [PATCH v8 09/14] ALSA: virtio: add staged capture accounting and lifecycle recovery Joonho Lee
2026-10-29 6:23 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 10/14] ALSA: virtio: prioritize staged capture period work Joonho Lee
2026-10-29 5:48 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 11/14] docs: describe virtio-sound capture options Joonho Lee
2026-10-29 5:47 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 12/14] ALSA: pcm: add an optional reset operation under the stream lock Joonho Lee
2026-10-29 5:52 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 13/14] ALSA: virtio: synchronize staged capture reset with PCM positions Joonho Lee
2026-10-29 6:05 ` sashiko-bot
2026-10-29 5:43 ` [PATCH v8 14/14] ALSA: virtio: synchronize indirect capture positions on reset Joonho Lee
2026-10-29 6:06 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-188788@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=linux-sound@vger.kernel.org \
--cc=mst@redhat.com \
--cc=mynameisjune111@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=virtualization@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox