mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Josef Schlehofer <pepe.schlehofer@gmail.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	Hyunwoo Kim <imv4bel@gmail.com>,
	Hans Verkuil <hverkuil@kernel.org>,
	stable@vger.kernel.org
Subject: [PATCH v2 5/6] media: dvb-core: dmxdev: wake up readers on release
Date: Sun,  4 Oct 2026 12:07:40 +0200	[thread overview]
Message-ID: <20261004100741.71711-6-pepe.schlehofer@gmail.com> (raw)
In-Reply-To: <20261004100741.71711-1-pepe.schlehofer@gmail.com>

dvb_dmxdev_release() sets dmxdev->exit and waits for open demux and DVR
files to close, but readers blocked in dvb_dmxdev_buffer_read() wait
only for data or buffer->error. Setting exit therefore does not wake a
blocked read or epoll wait. The release, for example on a USB
disconnect, then waits forever.

Wake the DVR and open filter wait queues on release, and make
dvb_dmxdev_buffer_read() also wait for exit and return -ENODEV once it
is set. Also return -ENODEV from dvb_demux_read() once exit is set, as
dvb_dvr_read() already does.

Check exit instead of storing -ENODEV in buffer->error. The buffer error
is cleared by the reader that reports it, and the section timeout and
ioctls such as DMX_STOP can overwrite or clear it. A second reader of
the same file could then miss the release and keep it waiting.

Blocking DMX_DQBUF waiters are not covered.

Fixes: 57861b432bda ("V4L/DVB (5511): Fix 2/3 for bug 7819: demux and dvr")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
---
v2: check dmxdev->exit in the readers instead of storing -ENODEV in the
buffer error. A reader could clear an -ENODEV set concurrently by the
release, as reported by Sashiko [1]. The section timeout and ioctls
such as DMX_STOP could also overwrite or clear it.

Pre-existing cases remain where the release waits for users that are
not woken up, such as a blocking DMX_DQBUF, or an ioctl that waits for
the filter mutex of a blocked read() while holding dmxdev->mutex. The
unlocked users check in dvb_dmxdev_release() also still races with a
concurrent close(), and waking the readers makes that race easier to
hit.

v1: https://lore.kernel.org/r/20260923001410.30297-6-pepe.schlehofer@gmail.com
[1] https://linuxtv.org/mailman3/hyperkitty/list/media-ci@linuxtv.org/message/N3XJE5MO4HP2LJYOKFHIRB564HATZCTI/

 drivers/media/dvb-core/dmxdev.c | 36 +++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 6a825d9bae43..8a744a96bc08 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -50,7 +50,8 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
 	return dvb_ringbuffer_write(buf, src, len);
 }
 
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev *dmxdev,
+				      struct dvb_ringbuffer *src,
 				      int non_blocking, char __user *buf,
 				      size_t count, loff_t *ppos)
 {
@@ -75,10 +76,16 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
 
 		ret = wait_event_interruptible(src->queue,
 					       !dvb_ringbuffer_empty(src) ||
-					       (src->error != 0));
+					       (src->error != 0) ||
+					       dmxdev->exit);
 		if (ret < 0)
 			break;
 
+		if (dmxdev->exit) {
+			ret = -ENODEV;
+			break;
+		}
+
 		if (src->error) {
 			ret = src->error;
 			dvb_ringbuffer_flush(src);
@@ -274,7 +281,7 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 	if (dmxdev->exit)
 		return -ENODEV;
 
-	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+	return dvb_dmxdev_buffer_read(dmxdev, &dmxdev->dvr_buffer,
 				      file->f_flags & O_NONBLOCK,
 				      buf, count, ppos);
 }
@@ -998,7 +1005,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
 		hcount = 3 + dfil->todo;
 		if (hcount > count)
 			hcount = count;
-		result = dvb_dmxdev_buffer_read(&dfil->buffer,
+		result = dvb_dmxdev_buffer_read(dfil->dev, &dfil->buffer,
 						file->f_flags & O_NONBLOCK,
 						buf, hcount, ppos);
 		if (result < 0) {
@@ -1019,7 +1026,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
 	}
 	if (count > dfil->todo)
 		count = dfil->todo;
-	result = dvb_dmxdev_buffer_read(&dfil->buffer,
+	result = dvb_dmxdev_buffer_read(dfil->dev, &dfil->buffer,
 					file->f_flags & O_NONBLOCK,
 					buf, count, ppos);
 	if (result < 0)
@@ -1035,13 +1042,17 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count,
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	int ret;
 
+	if (dmxdevfilter->dev->exit)
+		return -ENODEV;
+
 	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
 		return -ERESTARTSYS;
 
 	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
 		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
 	else
-		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+		ret = dvb_dmxdev_buffer_read(dmxdevfilter->dev,
+					     &dmxdevfilter->buffer,
 					     file->f_flags & O_NONBLOCK,
 					     buf, count, ppos);
 
@@ -1457,8 +1468,21 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
 
 void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
+	int i;
+
 	mutex_lock(&dmxdev->mutex);
 	dmxdev->exit = 1;
+
+	/*
+	 * Wake up everyone blocked in read() or poll() on the demux and dvr
+	 * devices, so that they get -ENODEV or EPOLLERR, close their file
+	 * handles and let the waits below finish.
+	 */
+	wake_up_all(&dmxdev->dvr_buffer.queue);
+	for (i = 0; i < dmxdev->filternum; i++) {
+		if (dmxdev->filter[i].state >= DMXDEV_STATE_ALLOCATED)
+			wake_up_all(&dmxdev->filter[i].buffer.queue);
+	}
 	mutex_unlock(&dmxdev->mutex);
 
 	if (dmxdev->dvbdev->users > 1) {
-- 
2.54.0 (Apple Git-157)


  parent reply	other threads:[~2026-10-04 10:07 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-04 10:07 [PATCH v2 0/6] media: az6007/drxk/dvb-core: cope with a tuner unplugged while in use Josef Schlehofer
2026-10-04 10:07 ` [PATCH v2 1/6] media: az6007: fix CAM status polling after disconnect Josef Schlehofer
2026-10-04 10:07 ` [PATCH v2 2/6] media: az6007: propagate USB errors from I2C transfers Josef Schlehofer
2026-10-04 10:07 ` [PATCH v2 3/6] media: drxk: stop retrying after disconnect Josef Schlehofer
2026-10-04 10:07 ` [PATCH v2 4/6] media: drxk: stop accessing a disconnected device Josef Schlehofer
2026-10-04 10:07 ` Josef Schlehofer [this message]
2026-10-04 10:07 ` [PATCH v2 6/6] media: dvb-core: wake up CA users on release Josef Schlehofer

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=20261004100741.71711-6-pepe.schlehofer@gmail.com \
    --to=pepe.schlehofer@gmail.com \
    --cc=hverkuil@kernel.org \
    --cc=imv4bel@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=stable@vger.kernel.org \
    /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

all inboxes | Powered by JetHome®