From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=74.125.82.177 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793156017; b=0i+2PhdkiU5LsZSgKmVgLCi41GcVpGzKRXVgL9f0xoLJueiBc7QYN14fDoYds5s69exB kFfgrkOEeLKurn+Y5wRYMKWv1qKghlvbxIn8aJH55jktzOhg8y2Odhwr4uf2iznvCbhF4 yzmPlgF7sEKMnrp12zjaf1Ph8AwEc0F/G8EtsuL6aTO+8L80MOcQqKKdl2QbMeFMtzz3I 4QV3AXr4ww4QNCcq7PH9b58pv53ljL/1BvlVW+hhwOmEelvyc2zpdNBLLAqjaWw0mZs4u Ef/FStpicAz67PCSDumQENQiEIKTC02Sr5/vK1m0jl6fsc9t3osSh/oiPHbqkGE7SyA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793156017; 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=kyQytzBiZOGLqfGD6DAtOxP6vHxS9tRRyPEOmCY+8K4=; b=FAZ7GRDhjqFdYYLNsfAvI8aZDcMq0Uus1cLZkqyYHU5T0gBIiVdOr45kHD75UaQc3T6I 0lLuxlt92vt97eH2BpISLzOQPXZt8ptakB3YNlxuUas9McpV5Pr/wSYbMA/zHMbcamV6c fXGqMnhBb/P+Z2ZRdHMXwdMkDcIniRLrGUwcmzoUybwVioGlvLIERXv6e3r0DHrrf/+Yq s03X/+Mfh3dHozC0ZH2ycYNVKc3s7ayMCK+TJStXUDy/eKd553zSdRQxpUoSkevY5IbJq cQSAqP1XoSk9t7wiIxdJkZrWzgtshRYwbLZV+bCSogLQ+ZV8J7VFKGOcKsxqC+0AdfQ== 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=jbtSD9Tu; arc=none smtp.remote-ip=74.125.82.177 Received: from mail-dy1-f177.google.com (mail-dy1-f177.google.com [74.125.82.177]) (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 16F3860A2602 for ; Wed, 28 Oct 2026 02:53:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 16F3860A2602 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, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=jbtSD9Tu Received: by mail-dy1-f177.google.com with SMTP id 5a478bee46e88-35b2c599f43so1092169eec.0 for ; Tue, 27 Oct 2026 19:53:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793156015; x=1793760815; 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=kyQytzBiZOGLqfGD6DAtOxP6vHxS9tRRyPEOmCY+8K4=; b=jbtSD9TuqUkBIT4qbuY82ePSqkln6d+aA4gQD0vMRi62+6G1lUR5gUsXM4lMEkOYzi N4i5v5Ysv3FkOIyjL6pbINC0dTuyx/goXM/mpPWJRByuSwaFeIHXzCStD9qBhExUI3W9 nbS94hTbbLbRkmbrl8KGzMQue3ox6ppEFfFqGYvSRzbqq7RPGDvJvvwzfRcVSLHEupeo gIIB5nhCS/ML0GAIYiGPn/qTzbRmfYZolK+GQYEfru1YCn23cJ+DuTqIv3u2apHpD18G /bjjHpvHWIFFEi7RipNzHB/5Si1JI75Ir5JZyaxHcscegpOWA1twMJ0hRPJinWTlit5T Q+lA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793156015; x=1793760815; 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=kyQytzBiZOGLqfGD6DAtOxP6vHxS9tRRyPEOmCY+8K4=; b=SLA6ofUU5pd3+36KZ9K/bJo6FCrqB1J0tjMa4JzbVhsZ6KIY6mUgNYMDvtLlaxOur/ 7UVFIEGiFo4JxQqtuiCPDYvflgu+nQtAJEx5F1Krmodz1anwwZQA3m5PiBF7fZu0G9bv ALrmgdPX9z9RJ3FrgwzWAt3hK5AMaMZqFo1coPH/3NAp5jEpkLq2S8QAFSDFf+GLnQAh DFpHV6qgjsQcxu3DSLuB6wNjHxfp6wPCQ2JRUSHRK1vDWdiGkn0PUb5pw/pfJ6UmLwET uySginJyP8YBffQ/V43x2yIqYW8kDkrASeUp+O/0YBQF8eSVqfcTHFNVuGEDv7yaMJGV w4YA== X-Forwarded-Encrypted: i=1; AKwUvBzaEkNpNnqxIyxSgZyP0+Z+RiZGQv5xYnLCyz0bEIHMtBhNPIS/fpxhClkMI11+M8vsVsY2kVynHWI=@vger.kernel.org X-Gm-Message-State: AFq9FYJoXqs1KFlvPDvpSQcGmUTg9RmcUNvYr+qD4VWgO7sWFhEKUHiI GkcuQymxC2YQlXUQm5WzLmrhMBFpt/yceSgNjQjWlGZ19fDlNwbshw6i X-Gm-Gg: AYBFou1qp+TW1ph9kZQ/kH8rWZwfQO+9x1P9+sWPu7IWqIt3Z/9jYcaSxM5XhIsESx4 vSjNsEb8HJG33c9LVoSqpWvk2gUEbILd9+coHny7B8neluWpsA1gPXMd7ePOvrpCv0XTlxmzuUG tJCoBf1f45/2+C6p97gw+hYTcde4nPgxKa3YIVEd6YDzoVXmaSNvY20RotDii5c+6oqDmqEWQt4 h6PdGZtfVqfyid3XQGin4kmCIkTls3uB65atnSMEvBlGdqS579cTlKDYjEfb5uYh/Vh7rPNKtUj lzuWUMII/171VxKE7cBQs6CT3zgwC8y0D91GpEBoFwBNrFRzKBASFzkw7nXcDNppuGYqc6RyRme NScwsZ3KP8EsSvGUO/CQLdlig4l2a7WD2SNIJDA6LLTEkB9JAv5oqXWArvLgFXWsNH6WJqIZCXe K7jaR8o70UFeb2YvuVpu7e6DWYdgMffuwd8X1aXIDLkY6vKOtUPx0fYzjC2N8gqxtB15Gf9sA5q Gmbc6PNlRwZOPmZZvXAwirx+p9Ef54KG4uUdf8cHWIKdaBqrN+P+dpnzuVtmTirX2VlWj40gM5b 9IiYwt3OC5Jer/tfVbz3iulEpgTMidxlay8bh3M2htdzNLXaWES6fpnBH3Gyz8PFqxjgJry5gjT arOdjcN6sd0t32zL1pp6izjnIaMJyRkMDkrq5dtUiMG2Rz7U= X-Received: by 2002:a05:7300:7316:b0:36a:22c8:ac57 with SMTP id 5a478bee46e88-36a22c8b078mr1310494eec.33.1793156015020; Tue, 27 Oct 2026 19:53:35 -0700 (PDT) Received: from localhost.localdomain ([183.96.175.225]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-36a239644efsm1711914eec.23.2026.10.27.19.53.32 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 27 Oct 2026 19:53:34 -0700 (PDT) From: Joonho Lee To: linux-sound@vger.kernel.org Cc: tiwai@suse.de, 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 v6 04/14] ALSA: virtio: Keep PCM DMA buffers alive through device ownership Date: Wed, 28 Oct 2026 11:53:07 +0900 Message-ID: <20261028025317.92450-5-mynameisjune111@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20261028025317.92450-1-mynameisjune111@gmail.com> References: <20261028025317.92450-1-mynameisjune111@gmail.com> X-Mailing-List: linux-doc@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 Retain references to the pages backing ALSA's vmalloc buffer until its queued I/O messages are freed. On NOMMU systems, use driver-owned memory for DMA and copy playback data before submission and capture data after completion, so ALSA buffer release cannot invalidate an active request. Validate the PCM buffer and each period before building scatterlists. Clamp device-reported capture lengths to the message capacity before advancing the hardware pointer, preventing an oversized completion from accounting bytes beyond the buffer actually submitted. Fixes: f40a28679e0b ("ALSA: virtio: handling control and I/O messages for the PCM device") Assisted-by: LLM Signed-off-by: Joonho Lee --- Changes in v3: - No code or commit-message changes from v2. sound/virtio/virtio_pcm.h | 11 ++ sound/virtio/virtio_pcm_msg.c | 252 +++++++++++++++++++++++++++++++--- sound/virtio/virtio_pcm_ops.c | 2 + 3 files changed, 243 insertions(+), 22 deletions(-) diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index e31f090a0124..61faf7b13cbc 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -13,6 +13,7 @@ struct virtio_pcm; struct virtio_pcm_msg; +struct page; /** * struct virtio_pcm_substream - VirtIO PCM substream. @@ -38,6 +39,10 @@ struct virtio_pcm_msg; * @msgs: Allocated I/O messages. * @nmsgs: Number of allocated I/O messages. * @msg_count: Number of pending I/O messages in the virtqueue. + * @dma_pages: Pages backing DMA messages, retained until messages are freed. + * @ndma_pages: Number of retained pages. + * @owned_dma_area: Driver-owned PCM buffer backing asynchronous messages. + * @owned_dma_bytes: Size of @owned_dma_area. * @msg_empty: Notify when msg_count is zero. */ struct virtio_pcm_substream { @@ -60,6 +65,12 @@ struct virtio_pcm_substream { struct virtio_pcm_msg **msgs; unsigned int nmsgs; unsigned int msg_count; + struct page **dma_pages; + unsigned int ndma_pages; +#ifndef CONFIG_MMU + u8 *owned_dma_area; + size_t owned_dma_bytes; +#endif wait_queue_head_t msg_empty; }; diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c index 762480363b86..b7f2334bb221 100644 --- a/sound/virtio/virtio_pcm_msg.c +++ b/sound/virtio/virtio_pcm_msg.c @@ -3,6 +3,9 @@ * virtio-snd: Virtio sound device * Copyright (C) 2021 OpenSynergy GmbH */ +#include +#include +#include #include #include "virtio_card.h" @@ -13,6 +16,7 @@ * @xfer: Request header payload. * @status: Response header payload. * @length: Data length in bytes. + * @data_offset: Offset in the driver-owned PCM buffer on NOMMU systems. * @sgs: Payload scatter-gather table. */ struct virtio_pcm_msg { @@ -20,6 +24,9 @@ struct virtio_pcm_msg { struct virtio_snd_pcm_xfer xfer; struct virtio_snd_pcm_status status; size_t length; +#ifndef CONFIG_MMU + size_t data_offset; +#endif struct scatterlist sgs[]; }; @@ -37,9 +44,8 @@ enum pcm_msg_sg_index { }; /** - * virtsnd_pcm_sg_num() - Count the number of sg-elements required to represent - * vmalloc'ed buffer. - * @data: Pointer to vmalloc'ed buffer. + * virtsnd_pcm_sg_num() - Count the sg-elements for a page-backed buffer. + * @data: Pointer to the page-backed buffer. * @length: Buffer size. * * Context: Any context. @@ -47,15 +53,19 @@ enum pcm_msg_sg_index { */ static int virtsnd_pcm_sg_num(u8 *data, unsigned int length) { - phys_addr_t sg_address; - unsigned int sg_length; + phys_addr_t sg_address = 0; + unsigned int sg_length = 0; int num = 0; while (length) { struct page *pg = vmalloc_to_page(data); - phys_addr_t pg_address = page_to_phys(pg); + phys_addr_t pg_address; size_t pg_length; + if (!pg) + return -EINVAL; + pg_address = page_to_phys(pg); + pg_length = PAGE_SIZE - offset_in_page(data); if (pg_length > length) pg_length = length; @@ -75,11 +85,80 @@ static int virtsnd_pcm_sg_num(u8 *data, unsigned int length) return num; } +#ifdef CONFIG_MMU +/** + * virtsnd_pcm_dma_pages_put() - Release retained PCM buffer pages. + * @vss: VirtIO PCM substream. + * + * Context: Process context. + */ +static void virtsnd_pcm_dma_pages_put(struct virtio_pcm_substream *vss) +{ + while (vss->ndma_pages) + put_page(vss->dma_pages[--vss->ndma_pages]); + kfree(vss->dma_pages); + vss->dma_pages = NULL; +} + /** - * virtsnd_pcm_sg_from() - Build sg-list from vmalloc'ed buffer. + * virtsnd_pcm_dma_pages_get() - Retain the pages backing the PCM buffer. + * @vss: VirtIO PCM substream. + * @data: PCM buffer address. + * @length: PCM buffer size. + * + * Keep the backing pages alive while virtqueue descriptors can still refer to + * them, even if ALSA releases the vmalloc mapping after a failed drain. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_dma_pages_get(struct virtio_pcm_substream *vss, + u8 *data, size_t length) +{ + size_t i; + size_t npages; + size_t span; + + if (!data || !length || !is_vmalloc_addr(data)) + return -EINVAL; + if (vss->dma_pages || vss->ndma_pages) + return -EBUSY; + + if (check_add_overflow(length, (size_t)offset_in_page(data), &span)) + return -EOVERFLOW; + + npages = span / PAGE_SIZE + !!(span % PAGE_SIZE); + if (npages > UINT_MAX) + return -EOVERFLOW; + + vss->dma_pages = kcalloc(npages, sizeof(*vss->dma_pages), GFP_KERNEL); + if (!vss->dma_pages) + return -ENOMEM; + + for (i = 0; i < npages; i++) { + struct page *page = vmalloc_to_page(data + i * PAGE_SIZE); + + if (!page) + goto err_put_pages; + + get_page(page); + vss->dma_pages[vss->ndma_pages++] = page; + } + + return 0; + +err_put_pages: + virtsnd_pcm_dma_pages_put(vss); + + return -EINVAL; +} +#endif + +/** + * virtsnd_pcm_sg_from() - Build an sg-list from a page-backed buffer. * @sgs: Preallocated sg-list to populate. * @nsgs: The maximum number of elements in the @sgs. - * @data: Pointer to vmalloc'ed buffer. + * @data: Pointer to the page-backed buffer. * @length: Buffer size. * * Splits the buffer into physically contiguous parts and makes an sg-list of @@ -132,36 +211,99 @@ static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data, int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss, unsigned int periods, unsigned int period_bytes) { - struct snd_pcm_runtime *runtime = vss->substream->runtime; + struct snd_pcm_runtime *runtime; + size_t buffer_bytes; unsigned int i; + int rc; - vss->msgs = kzalloc_objs(*vss->msgs, periods); - if (!vss->msgs) + if (vss->msgs || vss->nmsgs || vss->dma_pages || vss->ndma_pages) + return -EBUSY; +#ifndef CONFIG_MMU + if (vss->owned_dma_area || vss->owned_dma_bytes) + return -EBUSY; +#endif + if (!periods || !period_bytes) + return -EINVAL; + + if (check_mul_overflow((size_t)periods, (size_t)period_bytes, + &buffer_bytes)) + return -EOVERFLOW; + + if (!vss->substream || !vss->substream->runtime) + return -EINVAL; + runtime = vss->substream->runtime; + if (!runtime->dma_area || buffer_bytes > runtime->dma_bytes) + return -EINVAL; + +#ifdef CONFIG_MMU + rc = virtsnd_pcm_dma_pages_get(vss, runtime->dma_area, buffer_bytes); + if (rc) + return rc; +#else + vss->owned_dma_area = kzalloc(buffer_bytes, GFP_KERNEL); + if (!vss->owned_dma_area) return -ENOMEM; + vss->owned_dma_bytes = buffer_bytes; +#endif + + vss->msgs = kzalloc_objs(*vss->msgs, periods); + if (!vss->msgs) { + rc = -ENOMEM; + goto err_free_pages; + } vss->nmsgs = periods; for (i = 0; i < periods; ++i) { - u8 *data = runtime->dma_area + period_bytes * i; - int sg_num = virtsnd_pcm_sg_num(data, period_bytes); + int sg_num; struct virtio_pcm_msg *msg; + u8 *data; +#ifdef CONFIG_MMU + data = runtime->dma_area + (size_t)period_bytes * i; +#else + data = vss->owned_dma_area + (size_t)period_bytes * i; +#endif + sg_num = virtsnd_pcm_sg_num(data, period_bytes); + if (sg_num < 0) { + rc = sg_num; + goto err_free_msgs; + } msg = kzalloc_flex(*msg, sgs, sg_num + 2); - if (!msg) - return -ENOMEM; + if (!msg) { + rc = -ENOMEM; + goto err_free_msgs; + } msg->substream = vss; + vss->msgs[i] = msg; sg_init_one(&msg->sgs[PCM_MSG_SG_XFER], &msg->xfer, sizeof(msg->xfer)); sg_init_one(&msg->sgs[PCM_MSG_SG_STATUS], &msg->status, sizeof(msg->status)); +#ifndef CONFIG_MMU + msg->data_offset = (size_t)period_bytes * i; +#endif virtsnd_pcm_sg_from(&msg->sgs[PCM_MSG_SG_DATA], sg_num, data, period_bytes); - - vss->msgs[i] = msg; } return 0; + +err_free_msgs: + virtsnd_pcm_msg_free(vss); + return rc; + +err_free_pages: +#ifdef CONFIG_MMU + virtsnd_pcm_dma_pages_put(vss); +#else + kfree(vss->owned_dma_area); + vss->owned_dma_area = NULL; + vss->owned_dma_bytes = 0; +#endif + + return rc; } /** @@ -177,6 +319,13 @@ void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss) for (i = 0; vss->msgs && i < vss->nmsgs; ++i) kfree(vss->msgs[i]); kfree(vss->msgs); +#ifdef CONFIG_MMU + virtsnd_pcm_dma_pages_put(vss); +#else + kfree(vss->owned_dma_area); + vss->owned_dma_area = NULL; + vss->owned_dma_bytes = 0; +#endif vss->msgs = NULL; vss->nmsgs = 0; @@ -249,6 +398,33 @@ int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss, unsigned long offset, msg->xfer.stream_id = cpu_to_le32(vss->sid); memset(&msg->status, 0, sizeof(msg->status)); +#ifndef CONFIG_MMU + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) { + struct snd_pcm_runtime *runtime = + vss->substream ? vss->substream->runtime : NULL; + size_t data_bytes = msg->length; + + if (!runtime || !runtime->dma_area || !vss->owned_dma_area || + msg->data_offset > runtime->dma_bytes || + data_bytes > runtime->dma_bytes - msg->data_offset || + msg->data_offset > vss->owned_dma_bytes || + data_bytes > vss->owned_dma_bytes - msg->data_offset) { + dev_err_ratelimited(&vdev->dev, + "SID %u: invalid playback buffer for I/O message\n", + vss->sid); + msg->length -= n; + if (msg_count != vss->msg_count && + !(vss->features & + (1U << VIRTIO_SND_PCM_F_MSG_POLLING)) && + virtqueue_kick_prepare(vqueue)) + virtqueue_notify(vqueue); + return -EINVAL; + } + memcpy(vss->owned_dma_area + msg->data_offset, + runtime->dma_area + msg->data_offset, data_bytes); + } +#endif + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg, GFP_ATOMIC); @@ -363,15 +539,48 @@ static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, * the hw_ptr value is unconditionally advanced. */ guard(spinlock)(&vss->lock); +#ifndef CONFIG_MMU + if (vss->direction == SNDRV_PCM_STREAM_CAPTURE && + vss->xfer_enabled && written_bytes > sizeof(msg->status)) { + struct snd_pcm_runtime *runtime = + vss->substream ? vss->substream->runtime : NULL; + size_t reported_bytes = written_bytes - sizeof(msg->status); + size_t data_bytes = min_t(size_t, reported_bytes, msg->length); + + if (!runtime || !runtime->dma_area || !vss->owned_dma_area || + msg->data_offset > runtime->dma_bytes || + data_bytes > runtime->dma_bytes - msg->data_offset || + msg->data_offset > vss->owned_dma_bytes || + data_bytes > vss->owned_dma_bytes - msg->data_offset) + dev_err_ratelimited(&vss->snd->vdev->dev, + "SID %u: invalid capture buffer for I/O message\n", + vss->sid); + else + memcpy(runtime->dma_area + msg->data_offset, + vss->owned_dma_area + msg->data_offset, data_bytes); + } +#endif + if (vss->direction == SNDRV_PCM_STREAM_CAPTURE && + written_bytes > sizeof(msg->status) && + written_bytes - sizeof(msg->status) > msg->length) + dev_err_ratelimited(&vss->snd->vdev->dev, + "SID %u: capture length exceeds I/O message capacity\n", + vss->sid); /* * If the capture substream returned an incorrect status, then just - * increase the hw_ptr by the message size. + * increase the hw_ptr by the message size. Clamp valid capture lengths to + * the actual SG payload capacity before accounting them. */ if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK || - written_bytes <= sizeof(msg->status)) + written_bytes <= sizeof(msg->status)) { vss->hw_ptr += msg->length; - else - vss->hw_ptr += written_bytes - sizeof(msg->status); + } else { + size_t data_bytes = min_t(size_t, + written_bytes - sizeof(msg->status), + msg->length); + + vss->hw_ptr += data_bytes; + } if (vss->hw_ptr >= vss->buffer_bytes) vss->hw_ptr -= vss->buffer_bytes; @@ -387,7 +596,6 @@ static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, runtime->delay = bytes_to_frames(runtime, le32_to_cpu(msg->status.latency_bytes)); - schedule_work(&vss->elapsed_period); } else if (!vss->msg_count) { wake_up_all(&vss->msg_empty); diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c index 970499fe419b..f74bf365065b 100644 --- a/sound/virtio/virtio_pcm_ops.c +++ b/sound/virtio/virtio_pcm_ops.c @@ -25,6 +25,8 @@ * signal or due to a timeout. In this case, the device can still access * messages even after calling ops->hw_free(). It can also issue an interrupt, * and the interrupt handler will also try to access message structures. + * The messages retain references to the PCM buffer pages until they are + * freed, so late DMA does not target pages released by ALSA. * * Therefore, freeing of already allocated messages occurs: * -- 2.54.0 (Apple Git-157)