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 13/14] ALSA: virtio: synchronize staged capture reset with PCM positions
Date: Thu, 29 Oct 2026 06:05:58 +0000	[thread overview]
Message-ID: <sashiko-outbox-188791@kernel.org> (raw)
In-Reply-To: <20261029054354.2931-14-mynameisjune111@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ALSA: virtio: unupdated capture_notified_periods in virtsnd_pcm_reset()
- [High] ALSA: virtio: false XRUN and skipped rebase in virtsnd_pcm_reset() race
--

commit 4e51f7611d17678ff733d2492023b2e0abcb06d3
Author: Joonho Lee <mynameisjune111@gmail.com>

ALSA: virtio: synchronize staged capture reset with PCM positions

This commit introduces a custom PCM reset operation for staged capture
streams to synchronize private copied and acknowledged byte counters with
ALSA core pointer resets. When resetting a running stream, it calls
snd_pcm_lib_reset(), advances capture_acked_total to
capture_pointer_seen_total, and attempts to refill the RX queue.

> diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
> index 66560d82b7f8e..ba14f395eef8a 100644
> --- a/sound/virtio/virtio_pcm_ops.c
> +++ b/sound/virtio/virtio_pcm_ops.c

[ ... ]

> @@ -1591,6 +1598,58 @@ static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream)
>  	return virtsnd_pcm_sync_stop_locked(substream);
>  }
>  
> +/* The core holds the stream lock through the matching appl_ptr reset. */
> +static int virtsnd_pcm_reset(struct snd_pcm_substream *substream)
> +{
> +	struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream);
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss);
> +	size_t position;
> +	size_t period;
> +	int rc;
> +
> +	/* Keep ALSA's pointer validation, time accounting and XRUN processing. */
> +	rc = snd_pcm_lib_reset(substream);
> +	if (rc || !vss->capture_staging)
> +		return rc;
> +
> +	guard(spinlock_irqsave)(&queue->lock);
> +	guard(spinlock)(&vss->lock);
> +	if (vss->resetting)
> +		return -ECANCELED;
> +	/* The common reset has already handled a pointer-reported XRUN. */
> +	if (vss->xfer_xrun)
> +		return 0;

[Severity: High]
Can an RX completion arriving between snd_pcm_lib_reset() and acquiring
vss->lock trigger a false XRUN and skip the private counter rebase?

During snd_pcm_do_reset() -> virtsnd_pcm_reset(), snd_pcm_lib_reset() calls
virtsnd_pcm_cp_pointer(), which records vss->capture_pointer_seen_total and
releases vss->lock while vss->capture_ready still holds the pre-reset
unacknowledged byte count:

sound/virtio/virtio_pcm_ops.c:virtsnd_pcm_cp_pointer() {
    ...
				} else {
					vss->capture_pointer_seen_total = total;
					hw_ptr = virtsnd_pcm_ring_offset(total, vss->buffer_bytes);
				}
    ...
}

In managed mode (!vss->capture_free_running), if an in-flight RX completion
arrives before virtsnd_pcm_reset() acquires queue->lock and vss->lock,
virtsnd_pcm_capture_complete() checks the incoming bytes against the stale
pre-reset vss->capture_ready:

sound/virtio/virtio_pcm_msg.c:virtsnd_pcm_capture_complete() {
    ...
		else if (!free_running &&
			 audio_bytes >= vss->buffer_bytes - vss->capture_ready)
			invalid_reason = "ring_capacity";
		else if (!free_running &&
			 check_add_overflow(vss->capture_ready, audio_bytes,
					    &next_ready))
			invalid_reason = "ready_overflow";
		else if (!free_running && next_ready >= vss->buffer_bytes)
			invalid_reason = "ring_full";
    ...
}

When the pre-reset unacknowledged bytes plus audio_bytes reach
vss->buffer_bytes, virtsnd_pcm_capture_complete() rejects the completion,
drops the captured audio, and sets vss->xfer_xrun = true.

When virtsnd_pcm_reset() then acquires the locks, it sees vss->xfer_xrun and
returns 0 without updating vss->capture_acked_total, vss->capture_ready, or
vss->pcm_indirect.appl_ptr, even though snd_pcm_lib_reset() did not observe
the XRUN and snd_pcm_do_reset() proceeds to rebase runtime->status->hw_ptr
and runtime->control->appl_ptr.

> +	if (snd_pcm_running(substream)) {
> +		/* Keep completions arriving after the core's pointer observation. */
> +		vss->capture_acked_total = vss->capture_pointer_seen_total;
> +		vss->capture_ready = vss->capture_free_running ? 0 :
> +			vss->capture_copied_total - vss->capture_acked_total;
> +	} else {
> +		position = frames_to_bytes(runtime, runtime->status->hw_ptr);
> +		vss->hw_ptr = position;
> +		period = snd_pcm_lib_period_bytes(substream);
> +		vss->capture_copied_total = position;
> +		vss->capture_acked_total = position;
> +		vss->capture_pointer_seen_total = position;
> +		vss->capture_ready = 0;
> +		vss->capture_notified_periods = period ? position / period : 0;
> +	}

[Severity: High]
Should the running-stream branch in virtsnd_pcm_reset() also advance
vss->capture_notified_periods to match vss->capture_pointer_seen_total?

If a completion in virtsnd_pcm_capture_complete() crosses a period boundary
and schedules vss->elapsed_period, and userspace invokes
SNDRV_PCM_IOCTL_RESET before virtsnd_pcm_period_elapsed() acquires the PCM
stream lock, snd_pcm_lib_reset() -> snd_pcm_update_hw_ptr() ->
virtsnd_pcm_cp_pointer() observes the new vss->capture_copied_total and
updates vss->capture_pointer_seen_total.

In snd_pcm_do_reset(), the core then folds that position into
runtime->hw_ptr_interrupt:

sound/core/pcm_native.c:snd_pcm_do_reset() {
    ...
		runtime->hw_ptr_base = 0;
		runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
			runtime->status->hw_ptr % runtime->period_size;
		runtime->silence_start = runtime->status->hw_ptr;
		runtime->silence_filled = 0;
		runtime->control->appl_ptr = runtime->status->hw_ptr;
    ...
}

Because the running branch in virtsnd_pcm_reset() leaves
vss->capture_notified_periods at its pre-reset value, the pending
virtsnd_pcm_period_elapsed() worker later sees period_floor >
vss->capture_notified_periods for a period boundary already accounted for in
runtime->hw_ptr_interrupt:

sound/virtio/virtio_pcm.c:virtsnd_pcm_period_elapsed() {
    ...
			period_floor = div64_ul(vss->capture_copied_total, period_bytes);
			if (period_floor > vss->capture_notified_periods) {
				/* Reserve crossed boundaries before the callback. */
				vss->capture_notified_periods = period_floor;
				notify = true;
			}
    ...
}

This triggers a duplicate snd_pcm_period_elapsed_under_stream_lock() ->
snd_pcm_update_hw_ptr0(substream, 1) call where delta > new_hw_ptr:

sound/core/pcm_lib.c:snd_pcm_update_hw_ptr0() {
    ...
	if (in_interrupt) {
		/* we know that one period was processed */
		/* delta = "expected next hw_ptr" for in_interrupt != 0 */
		delta = runtime->hw_ptr_interrupt + runtime->period_size;
		if (delta > new_hw_ptr) {
			/* check for double acknowledged interrupts */
			hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
			if (hdelta > runtime->hw_ptr_buffer_jiffies/2 + 1) {
				hw_base += runtime->buffer_size;
    ...
}

If the jiffies delta exceeds half the buffer duration, snd_pcm_update_hw_ptr0()
treats the duplicate notification as a missed full-buffer wrap-around and
advances runtime->status->hw_ptr by a full buffer_size of uncaptured frames.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261029054354.2931-1-mynameisjune111@gmail.com?part=13

  reply	other threads:[~2026-10-29  6:05 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
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 [this message]
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-188791@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.