From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=74.125.82.171 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794062082; b=KOTXu2X4G4SaQmUiTC4ceppAKd8zcK20bXqKmFUM4Jzi6ztCXOsDpta0xzlAWwM51lLG Yxglpj29TG6AoC/zbvAwL28lEwP37vJqyfhEKSCWGhMManxX0RQhqEiAOuYU6I0UPzTsT I116ap2qpRlL53GwVuz1jJDQ+Ch8uqNVHt41z2MOVPY/+xa9p/y/vjzli/FEpNeV5j9ox l/sDkQb5BJcJHqDMNeLQGBNPvESUiTjqtjKytWHBMhLBF4Nz7em7EseTQPkVwAMUD4umw sTg2IcLzGdaIrA2youNjs3rRuPgU3EYyivz75YasgUhGqIx9kspN5kR3HSxGV8c3vgw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794062082; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=RBzTR6XekcqDka7VZzelkfmXzQMAZ+MkrgZWgbkdMfs=; b=lOZIvKu6rese8fV81JfhioDmKcnX8ZQNleSiNA9pxLc+U52avcO9Eu8KMtINg17pVbGM Gq7UOTjMHtgEqcVtz8nWtMx2stN3SbL/8fsw9+iO6k4LN4JVeYAX/YHevuRBhjINUdYyX go/p5bOjjrVZ7hnUnBXahKvZN/kWhVMJDtdIcdWX/bjGlJ4LV67AQy0VzD6txrHekWYj9 wiLBgMY7cZRI2stTAzP2PHxHyR3BwBeuAliK6dMyVatciw+DKPIPK5n8fXUykJ+C32/U7 Q0+UrGRbbto9g2f3VnJ2PppysDfsL5fO+C9uyJwqXho+SX3MKxpoyQsxwgvWQFzEYoQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=FRPPN9IP; arc=none smtp.remote-ip=74.125.82.171 Received: from mail-dy1-f171.google.com (mail-dy1-f171.google.com [74.125.82.171]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4DF4F606EEBE for ; Sat, 7 Nov 2026 14:34:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 4DF4F606EEBE Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=FRPPN9IP Received: by mail-dy1-f171.google.com with SMTP id 5a478bee46e88-37071c0f42aso2156116eec.0 for ; Sat, 07 Nov 2026 06:34:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1794062081; x=1794666881; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RBzTR6XekcqDka7VZzelkfmXzQMAZ+MkrgZWgbkdMfs=; b=FRPPN9IPcXy0SbVxP9J1I97F816sP1L74RaBLB25WJNqvF1oDmTdKab1M38/XbsctY ZZzfpntKXzK6eaRE5lL8mVMkasi0/HokbFYu7SR1bEVvV16ctoXwq7ZV6HRWcYRTPNmg r1DsHGAPtpv6Jp6KRhFDAqlBQSaXHmGy1VC4iZvbI4O9SJ6+BIWEcHfOfsoQeZoiHfFO /jH1nMFvk1EJTMmLBNLS5YVkpZCTKTlq560OJuIV1egdGfX0u5t2qP3hmKpN7sjkjl2o F4uOpHDV8cqEmXRAU8hhPc6O5XdKNgfibri/HEDIMSTsm+5WkGbIssDalOgE+1ABWrGF fXnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794062081; x=1794666881; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=RBzTR6XekcqDka7VZzelkfmXzQMAZ+MkrgZWgbkdMfs=; b=q4uGQYESATApNHQDyjhSpPLBIkaJax9arEpxxvRcCADNLIRbbmIQjU6ZnaCj2aYoGh XUCCnpclD8D1xwzNS9764gkkshAJWwCGhpnGy3tifDvjQdvOuBsg34Gf46h3/QZP0PmO e2n8L8ybdfA3NcYi1waXOupQNZHZfLVBUsq1reoRuEJGd3IRUzEvZION3lqFIOarXyhz UpzCOOtQHYGSJYBv5/c8LIGDp95qpQYBCYGEyHe5lK/s9FkUpOrV+VoC6b4+SbD6NA98 y+O7m2o1mHGbkFIxS3S8OFVxAnRr0uP4tDxgWwu5krAp6mGJMfxHlysjKj9kHz0J8LSs dvlQ== X-Forwarded-Encrypted: i=1; AL+hErGwjbTYnYI9bN+1Xh72BGEvcCQ2ERDooEKRgTWJ4W7+vD144SkmgIPUQ/Lm21iwQuKayKB8VvPA1pYX57Q=@vger.kernel.org X-Gm-Message-State: APuU4Z8Y+RI+KZrnVvN5TzAk05Uu27RFy7fzQUFtl2OyGtZUHrWNEvVn aCqZaWeD2afee+TLIKZnVlxZt1C+sf2Jr5qBFY580cRmODjEqjOW2UEu X-Gm-Gg: AYBFou2YzVuQffO3IU1JH1h297BDjJtYnFKWvWk8bgyCIhSQuKHlvtboUY8hTnNyCJj TCLKw8WYGjEVnn2hF6kn+bJIfZgXqJtRB+A6QjEnJx3NItABUfBYow9kM7vAkyP583MnuAPIOVE YmPbG8M2Cta7TUDc//w2FftZTwh39J3Amk/DYz1hlqU5o9peAypl+BO47ue4hm16uBlN2AtAm7y 6Q1v96YrubfF60hdcZb+z1RqLoBfm+Q+dcD3EM7qNEwlMmeKms7VEMxCd7e1qgr83HL50oD7C+5 ThMN0+haaIl5v6EWtDx55DfrJEHCNHIqZmsaMFeTUMt+iP211M5ElCes9tnP+v2AlfNkLwAjEy5 jWqnkYMgXwHQCVBM7LDg2iLdpFHyA8ZB0MGOLL7KQKTIOZU8D83diQjlYFizb3+4xuVPDRcpVy4 CBjdS7YjiWlk4+Ghd3PDbdE1am3oIw2sJUaRMSvPXwFhPPyLl2US2QJsGQ9v2bXH8pppcnQ88Tt 60Yr2xhQrJsnWF08ExCro8tZMdpsFrV2+Izrdzt9FFO24kFb450BW+igrmz3Zb+fKTMLQ4+R0j+ 8cYfiRqSiAmSyIYJxcYaKIUk4GxdKwCS5kij6TXbGwXCA7uv+55srlOt0XWi/BiSIGcqYiMtD+a vM0HqjLZWcDhY9U5icUOi1bz7Cn5ZXObDW78kwMDZA1U16A== X-Received: by 2002:a05:693c:20c8:10b0:36a:30b:5dc0 with SMTP id 5a478bee46e88-36f75838341mr7270438eec.24.1794062081145; Sat, 07 Nov 2026 06:34:41 -0800 (PST) Received: from localhost.localdomain ([180.182.24.11]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-36fa9aea75fsm27881873eec.15.2026.11.07.06.34.37 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 07 Nov 2026 06:34:40 -0800 (PST) From: Joonho Lee To: linux-sound@vger.kernel.org Cc: tiwai@suse.com, perex@perex.cz, anton.yakovlev@opensynergy.com, mst@redhat.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, corbet@lwn.net, skhan@linuxfoundation.org, rdunlap@infradead.org, linux-doc@vger.kernel.org, Joonho Lee Subject: [PATCH v20 04/12] ALSA: virtio: Propagate PCM send failures through ACK Date: Sat, 7 Nov 2026 23:34:14 +0900 Message-ID: <20261107143422.29319-5-mynameisjune111@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20261107143422.29319-1-mynameisjune111@gmail.com> References: <20261107143422.29319-1-mynameisjune111@gmail.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit virtsnd_pcm_msg_send() can fail while queueing a transfer. Restore the failed message's length and notify the device about earlier messages queued by the same call, so they do not remain stranded. Propagate errors through the indirect transfer callback and commit its private cursor only after successful submission. Genuine transfer errors arm stop_operating and return -EPIPE so ALSA can retire the stream. Close ACK admission under the PCM stream lock before sleeping teardown. Keep the prepared state protected by the substream lock and reject ACK through prepare and parameter changes. Reopen admission in the reset callback while the core holds the PCM lock for its pointer rebase. An ACK racing with teardown returns -EBADFD and preserves stop state. Keep the polling feature path unchanged. Fixes: fe981e67568c ("ALSA: virtio: use ack callback") Reject a stopped playback ACK before the XRUN path can rearm stop_operating. For capture, allow the ordinary stopped tail only during DRAINING and only while no transfer XRUN is latched. Latch a transfer failure before stopping PCM work. Once core reports the member XRUN, ACK returns -EBADFD to avoid another linked XRUN. ACK during prepare remains rejected until the core state reaches PREPARED. Signed-off-by: Joonho Lee --- sound/virtio/virtio_pcm.h | 6 + sound/virtio/virtio_pcm_msg.c | 12 ++ sound/virtio/virtio_pcm_ops.c | 250 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 242 insertions(+), 26 deletions(-) diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -33,6 +33,10 @@ * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). * @stopped: True if the substream is stopped and must be released on the device * side. + * @prepared: True after device PREPARE and the core pointer reset succeed; + * protected by @lock. + * @preparing: ACK gate through teardown and prepare's core reset; + * protected by @lock. * @suspended: True if the substream is suspended and must be reconfigured on * the device side at resume. * @msgs: Allocated I/O messages. @@ -56,6 +60,8 @@ bool xfer_enabled; bool xfer_xrun; bool stopped; + bool prepared; + bool preparing; bool suspended; struct virtio_pcm_msg **msgs; unsigned int nmsgs; diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c --- a/sound/virtio/virtio_pcm_msg.c +++ b/sound/virtio/virtio_pcm_msg.c @@ -260,6 +260,18 @@ dev_err(&vdev->dev, "SID %u: failed to send I/O message\n", vss->sid); + msg->length -= n; + + /* + * Do not leave earlier messages queued without notifying + * the device when a later message could not be added. + */ + if (msg_count != vss->msg_count && + !(vss->features & + (1U << VIRTIO_SND_PCM_F_MSG_POLLING)) && + virtqueue_kick_prepare(vqueue)) + virtqueue_notify(vqueue); + return rc; } diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c --- a/sound/virtio/virtio_pcm_ops.c +++ b/sound/virtio/virtio_pcm_ops.c @@ -97,6 +97,38 @@ static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream); /** + * virtsnd_pcm_close_ack() - Update PCM prepare admission state. + * @substream: Kernel ALSA substream. + * @preparing: True while driver prepare and the core pointer reset are active. + * + * Context: Process context. + */ +static void virtsnd_pcm_close_ack(struct snd_pcm_substream *substream, + bool preparing) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + + scoped_guard(pcm_stream_lock_irqsave, substream) { + guard(spinlock_irqsave)(&vss->lock); + vss->prepared = false; + vss->xfer_enabled = false; + vss->preparing = preparing; + } +} + +/* Keep completed RX data valid while RELEASE drains the device queue. */ +static void virtsnd_pcm_block_ack(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + + scoped_guard(pcm_stream_lock_irqsave, substream) { + guard(spinlock_irqsave)(&vss->lock); + vss->preparing = true; + vss->xfer_enabled = false; + } +} + +/** * virtsnd_pcm_open() - Open the PCM substream. * @substream: Kernel ALSA substream. * @@ -115,7 +147,8 @@ snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); - vss->stopped = !!virtsnd_pcm_msg_pending_num(vss); + scoped_guard(spinlock_irqsave, &vss->lock) + vss->stopped = !!vss->msg_count; vss->suspended = false; /* @@ -219,6 +252,8 @@ struct virtio_device *vdev = vss->snd->vdev; int rc; + virtsnd_pcm_close_ack(substream, false); + if (virtsnd_pcm_msg_pending_num(vss)) { dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", vss->sid); @@ -254,6 +289,8 @@ { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + virtsnd_pcm_close_ack(substream, false); + /* If the queue is flushed, we can safely free the messages here. */ if (!virtsnd_pcm_msg_pending_num(vss)) virtsnd_pcm_msg_free(vss); @@ -262,17 +299,18 @@ } /** - * virtsnd_pcm_prepare() - Prepare the PCM substream. + * virtsnd_pcm_prepare_device() - Prepare the PCM substream on the device. * @substream: Kernel ALSA substream. * * Context: Process context. * Return: 0 on success, -errno on failure. */ -static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) +static int virtsnd_pcm_prepare_device(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); struct virtio_device *vdev = vss->snd->vdev; struct virtio_snd_msg *msg; + int rc; if (!vss->suspended) { if (virtsnd_pcm_msg_pending_num(vss)) { @@ -287,16 +325,14 @@ struct snd_pcm_runtime *runtime = substream->runtime; unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream); unsigned int period_bytes = snd_pcm_lib_period_bytes(substream); - int rc; rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes, - runtime->channels, - runtime->format, runtime->rate); + runtime->channels, + runtime->format, runtime->rate); if (rc) return rc; } - vss->xfer_xrun = false; vss->suspended = false; vss->msg_count = 0; virtsnd_pcm_msg_reset(vss); @@ -311,7 +347,26 @@ if (!msg) return -ENOMEM; - return virtsnd_ctl_msg_send_sync(vss->snd, msg); + rc = virtsnd_ctl_msg_send_sync(vss->snd, msg); + if (rc) + return rc; + + scoped_guard(spinlock_irqsave, &vss->lock) { + vss->xfer_xrun = false; + } + return 0; +} + +/* Keep ACK closed through the core's locked pointer reset. */ +static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) +{ + int rc; + + virtsnd_pcm_close_ack(substream, true); + rc = virtsnd_pcm_prepare_device(substream); + if (rc) + virtsnd_pcm_close_ack(substream, false); + return rc; } /** @@ -338,6 +393,8 @@ scoped_guard(spinlock_irqsave, &queue->lock) { guard(spinlock)(&vss->lock); + if (vss->preparing || !vss->prepared) + return -EBADFD; if (vss->direction == SNDRV_PCM_STREAM_CAPTURE) rc = virtsnd_pcm_msg_send(vss, 0, vss->buffer_bytes); if (rc) @@ -356,10 +413,12 @@ return virtsnd_ctl_msg_send_sync(snd, msg); case SNDRV_PCM_TRIGGER_SUSPEND: - vss->suspended = true; + scoped_guard(spinlock_irqsave, &vss->lock) + vss->suspended = true; fallthrough; case SNDRV_PCM_TRIGGER_STOP: - vss->stopped = true; + scoped_guard(spinlock_irqsave, &vss->lock) + vss->stopped = true; fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: scoped_guard(spinlock_irqsave, &vss->lock) { @@ -393,11 +452,16 @@ struct virtio_snd *snd = vss->snd; struct virtio_snd_msg *msg; unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms); + bool stopped; int rc; + virtsnd_pcm_block_ack(substream); + cancel_work_sync(&vss->elapsed_period); - if (!vss->stopped) + scoped_guard(spinlock_irqsave, &vss->lock) + stopped = vss->stopped; + if (!stopped) return 0; msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE, @@ -425,7 +489,8 @@ return !rc ? -ETIMEDOUT : rc; } - vss->stopped = false; + scoped_guard(spinlock_irqsave, &vss->lock) + vss->stopped = false; return 0; } @@ -442,6 +507,10 @@ virtsnd_pcm_pb_pointer(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + + scoped_guard(spinlock_irqsave, &vss->lock) + if (vss->xfer_xrun) + return SNDRV_PCM_POS_XRUN; return snd_pcm_indirect_playback_pointer(substream, &vss->pcm_indirect, @@ -461,41 +530,168 @@ { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + scoped_guard(spinlock_irqsave, &vss->lock) + if (vss->xfer_xrun) + return SNDRV_PCM_POS_XRUN; + return snd_pcm_indirect_capture_pointer(substream, &vss->pcm_indirect, vss->hw_ptr); } +struct virtsnd_pcm_transfer { + struct snd_pcm_indirect indirect; + int error; +}; + static void virtsnd_pcm_trans_copy(struct snd_pcm_substream *substream, struct snd_pcm_indirect *rec, size_t bytes) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); - - virtsnd_pcm_msg_send(vss, rec->sw_data, bytes); + struct virtsnd_pcm_transfer *transfer = + container_of(rec, struct virtsnd_pcm_transfer, indirect); + + if (transfer->error) + return; + + transfer->error = virtsnd_pcm_msg_send(vss, rec->sw_data, bytes); +} + +/* Caller holds vss->lock. */ +static void virtsnd_pcm_transfer_failed(struct virtio_pcm_substream *vss) +{ + vss->xfer_enabled = false; + vss->stopped = true; + vss->xfer_xrun = true; + vss->substream->runtime->stop_operating = true; +} + +/* The caller holds the PCM lock, also used by DROP and state transitions. */ +static int virtsnd_pcm_ack_state(struct snd_pcm_substream *substream) +{ + switch (substream->runtime->state) { + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PAUSED: + case SNDRV_PCM_STATE_DRAINING: + if (atomic_read(&substream->runtime->buffer_accessing) < 0) + return -EBADFD; + return 0; + default: + return -EBADFD; + } } static int virtsnd_pcm_pb_ack(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss); - - guard(spinlock_irqsave)(&queue->lock); - guard(spinlock)(&vss->lock); - - return snd_pcm_indirect_playback_transfer(substream, &vss->pcm_indirect, - virtsnd_pcm_trans_copy); + struct virtsnd_pcm_transfer transfer = {}; + int rc; + + rc = virtsnd_pcm_ack_state(substream); + if (rc) + return rc; + + scoped_guard(spinlock_irqsave, &queue->lock) { + guard(spinlock)(&vss->lock); + if (vss->preparing || !vss->prepared) + return -EBADFD; + if (vss->stopped) + return -EBADFD; + if (vss->xfer_xrun) { + rc = -EPIPE; + } else { + transfer.indirect = vss->pcm_indirect; + rc = snd_pcm_indirect_playback_transfer(substream, + &transfer.indirect, + virtsnd_pcm_trans_copy); + if (!rc) + rc = transfer.error; + } + if (rc) + virtsnd_pcm_transfer_failed(vss); + else + vss->pcm_indirect = transfer.indirect; + } + if (rc) { + dev_err(&vss->snd->vdev->dev, + "SID %u: playback ACK transfer failed: %d\n", + vss->sid, rc); + return -EPIPE; + } + + return 0; } static int virtsnd_pcm_cp_ack(struct snd_pcm_substream *substream) { struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); struct virtio_snd_queue *queue = virtsnd_pcm_queue(vss); - - guard(spinlock_irqsave)(&queue->lock); - guard(spinlock)(&vss->lock); - - return snd_pcm_indirect_capture_transfer(substream, &vss->pcm_indirect, - virtsnd_pcm_trans_copy); + struct virtsnd_pcm_transfer transfer = {}; + int rc; + + rc = virtsnd_pcm_ack_state(substream); + if (rc) + return rc; + + scoped_guard(spinlock_irqsave, &queue->lock) { + guard(spinlock)(&vss->lock); + if (vss->preparing || !vss->prepared) + return -EBADFD; + /* Keep only the post-STOP capture tail available during drain. */ + if (vss->stopped && + (vss->xfer_xrun || + substream->runtime->state != SNDRV_PCM_STATE_DRAINING)) + return -EBADFD; + if (vss->xfer_xrun) { + rc = -EPIPE; + } else { + transfer.indirect = vss->pcm_indirect; + rc = snd_pcm_indirect_capture_transfer(substream, + &transfer.indirect, + virtsnd_pcm_trans_copy); + if (!rc) + rc = transfer.error; + } + if (rc) + virtsnd_pcm_transfer_failed(vss); + else + vss->pcm_indirect = transfer.indirect; + } + if (rc) { + dev_err(&vss->snd->vdev->dev, + "SID %u: capture ACK transfer failed: %d\n", + vss->sid, rc); + return -EPIPE; + } + + return 0; +} + +/** + * virtsnd_pcm_reset() - Reset PCM pointers and complete prepare admission. + * @substream: Kernel ALSA substream. + * + * Context: PCM stream lock held. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_reset(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + int rc; + + rc = snd_pcm_lib_reset(substream); + scoped_guard(spinlock_irqsave, &vss->lock) { + if (vss->preparing) { + vss->prepared = !rc; + vss->preparing = false; + } + } + + return rc; } /* PCM substream operators map. */ @@ -507,6 +703,7 @@ .hw_params = virtsnd_pcm_hw_params, .hw_free = virtsnd_pcm_hw_free, .prepare = virtsnd_pcm_prepare, + .reset = virtsnd_pcm_reset, .trigger = virtsnd_pcm_trigger, .sync_stop = virtsnd_pcm_sync_stop, .pointer = virtsnd_pcm_pb_pointer, @@ -519,6 +716,7 @@ .hw_params = virtsnd_pcm_hw_params, .hw_free = virtsnd_pcm_hw_free, .prepare = virtsnd_pcm_prepare, + .reset = virtsnd_pcm_reset, .trigger = virtsnd_pcm_trigger, .sync_stop = virtsnd_pcm_sync_stop, .pointer = virtsnd_pcm_cp_pointer,