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
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox