All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.