public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Hans Verkuil <hverkuil@xs4all.nl>,
	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>,
	Sasha Levin <sashal@kernel.org>,
	mchehab@kernel.org, hverkuil@kernel.org,
	neil.armstrong@linaro.org, mingo@kernel.org, tglx@kernel.org,
	yelangyan@huaqin.corp-partner.google.com, rongqianfeng@vivo.com,
	linux-media@vger.kernel.org
Subject: [PATCH AUTOSEL 6.19-5.10] media: dvb-core: dmxdevfilter must always flush bufs
Date: Fri, 13 Feb 2026 19:59:49 -0500	[thread overview]
Message-ID: <20260214010245.3671907-109-sashal@kernel.org> (raw)
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>

From: Hans Verkuil <hverkuil@xs4all.nl>

[ Upstream commit c4e620eccbef76aa5564ebb295e23d6540e27215 ]

Currently the buffers are being filled until full, which works fine
for the transport stream, but not when reading sections, those have
to be returned to userspace immediately, otherwise dvbv5-scan will
just wait forever.

Add a 'flush' argument to dvb_vb2_fill_buffer to indicate whether
the buffer must be flushed or wait until it is full.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis

### 1. Commit Message Analysis

The commit clearly describes a functional bug: DVB section data is
buffered until the VB2 buffer is completely full, but sections are
discrete units that must be delivered immediately. The result is that
`dvbv5-scan` (a standard DVB channel scanning utility from v4l-utils)
**hangs forever** when using the VB2 mmap path.

### 2. Code Change Analysis

The bug is in `dvb_vb2_fill_buffer()` at line 309 of `dvb_vb2.c`:

```309:309:drivers/media/dvb-core/dvb_vb2.c
        if (ctx->nonblocking && ctx->buf) {
```

This condition flushes partially-filled buffers only when the file
descriptor was opened with `O_NONBLOCK`. The `nonblocking` field is set
during `dvb_vb2_init()` from `file->f_flags & O_NONBLOCK`:

```819:820:drivers/media/dvb-core/dmxdev.c
        dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
                     file->f_flags & O_NONBLOCK);
```

**The fundamental problem**: The decision to flush a partially-filled
buffer should depend on the **type of data** (section vs. transport
stream), not on the **blocking mode** of the file descriptor. DVB
sections are discrete protocol data units that must be returned to
userspace immediately. Transport streams are continuous, so waiting
until the buffer is full is correct.

**Bug mechanism**:
1. Application opens demux device in blocking mode (normal, no
   `O_NONBLOCK`)
2. `ctx->nonblocking` is set to 0
3. Section callback delivers a complete section to
   `dvb_vb2_fill_buffer()`
4. Section data is smaller than the full VB2 buffer, so `ctx->remain >
   0`
5. The `if (ctx->nonblocking && ctx->buf)` check fails (nonblocking=0)
6. Buffer is NOT flushed to userspace
7. Application blocks forever waiting for data that's already been
   received

**The fix** adds a `bool flush` parameter to `dvb_vb2_fill_buffer()`:
- `dvb_dmxdev_section_callback()` passes `flush=true` (sections: flush
  immediately)
- `dvb_dmxdev_ts_callback()` passes `flush=false` (transport stream:
  wait until full)
- The condition becomes `if (flush && ctx->buf)` - semantically correct

The `nonblocking` field is NOT removed - it's still used in
`dvb_vb2_dqbuf()` (line 415) for its legitimate purpose of controlling
blocking dequeue behavior.

### 3. Classification

This is a **clear bug fix** - it fixes a condition where a standard
userspace application (`dvbv5-scan`) hangs indefinitely. The existing
behavior was simply wrong: flushing decisions were tied to an unrelated
flag.

### 4. Scope and Risk Assessment

- **Files changed**: 3 (dmxdev.c, dvb_vb2.c, dvb_vb2.h)
- **Lines changed**: ~15 (very small)
- **Only 2 callers** of `dvb_vb2_fill_buffer()`, both updated
- **Internal API only** - no userspace-visible changes
- **TS path unchanged** - `flush=false` preserves existing behavior for
  transport streams
- **Section path fixed** - `flush=true` ensures proper delivery
- **CONFIG_DVB_MMAP only** - behind experimental Kconfig (default N),
  limiting blast radius
- **Risk**: Very low - the change cannot regress TS behavior, and
  section behavior goes from "broken" to "working"

### 5. User Impact

For users who have `CONFIG_DVB_MMAP` enabled and use `dvbv5-scan` or
similar section-reading applications via the VB2 path in blocking mode,
this is a **complete showstopper** - the application hangs forever.
Without this fix, the VB2 mmap path is fundamentally broken for section
data.

### 6. Stability Indicators

- **Author**: Hans Verkuil - V4L2/DVB subsystem maintainer, extremely
  well-known and trusted
- **Sign-off**: Mauro Carvalho Chehab - overall media subsystem
  maintainer
- **Self-contained**: No dependencies on other patches
- **Bug exists since**: The DVB VB2 feature was introduced in kernel
  4.20 (commit 57868acc369a), and this bug has existed since then

### 7. Dependency Check

The patch applies cleanly to the current tree. There are no dependencies
on other uncommitted patches. All callers are updated within the same
patch.

### Conclusion

This commit fixes a real, user-impacting bug where DVB section data is
never delivered to userspace through the VB2 mmap path when the file
descriptor is opened in blocking mode. The fix is small, self-contained,
obviously correct, and authored by the subsystem maintainer. The risk of
regression is minimal since the TS path behavior is preserved unchanged
and the section path goes from "broken" to "correct." While it only
affects `CONFIG_DVB_MMAP` (experimental), for users who enable it, the
bug is a complete showstopper.

**YES**

 drivers/media/dvb-core/dmxdev.c  | 8 ++++----
 drivers/media/dvb-core/dvb_vb2.c | 5 +++--
 include/media/dvb_vb2.h          | 6 ++++--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 8c6f5aafda1d6..17184b3674904 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -397,11 +397,11 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
 	if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
 		ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
 					  buffer1, buffer1_len,
-					  buffer_flags);
+					  buffer_flags, true);
 		if (ret == buffer1_len)
 			ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
 						  buffer2, buffer2_len,
-						  buffer_flags);
+						  buffer_flags, true);
 	} else {
 		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
 					      buffer1, buffer1_len);
@@ -452,10 +452,10 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
 
 	if (dvb_vb2_is_streaming(ctx)) {
 		ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
-					  buffer_flags);
+					  buffer_flags, false);
 		if (ret == buffer1_len)
 			ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
-						  buffer_flags);
+						  buffer_flags, false);
 	} else {
 		if (buffer->error) {
 			spin_unlock(&dmxdevfilter->dev->lock);
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 29edaaff7a5c9..7444bbc2f24d9 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -249,7 +249,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx)
 
 int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
 			const unsigned char *src, int len,
-			enum dmx_buffer_flags *buffer_flags)
+			enum dmx_buffer_flags *buffer_flags,
+			bool flush)
 {
 	unsigned long flags = 0;
 	void *vbuf = NULL;
@@ -306,7 +307,7 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
 		}
 	}
 
-	if (ctx->nonblocking && ctx->buf) {
+	if (flush && ctx->buf) {
 		vb2_set_plane_payload(&ctx->buf->vb, 0, ll);
 		vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
 		list_del(&ctx->buf->list);
diff --git a/include/media/dvb_vb2.h b/include/media/dvb_vb2.h
index 8cb88452cd6c2..0fbbfc65157e6 100644
--- a/include/media/dvb_vb2.h
+++ b/include/media/dvb_vb2.h
@@ -124,7 +124,7 @@ static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
 	return 0;
 };
 #define dvb_vb2_is_streaming(ctx) (0)
-#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0)
+#define dvb_vb2_fill_buffer(ctx, file, wait, flags, flush) (0)
 
 static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
 				    struct file *file,
@@ -166,10 +166,12 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx);
  * @buffer_flags:
  *		pointer to buffer flags as defined by &enum dmx_buffer_flags.
  *		can be NULL.
+ * @flush:	flush the buffer, even if it isn't full.
  */
 int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
 			const unsigned char *src, int len,
-			enum dmx_buffer_flags *buffer_flags);
+			enum dmx_buffer_flags *buffer_flags,
+			bool flush);
 
 /**
  * dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV
-- 
2.51.0


      parent reply	other threads:[~2026-02-14  1:07 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-14  0:58 [PATCH AUTOSEL 6.19-6.12] media: ipu6: Close firmware streams on streaming enable failure Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Fix conditional in start_streaming Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Avoid a reset low spike during probe() Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.1] media: amphion: Clear last_buffer_dequeued flag for DEC_CMD_START Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-5.10] media: adv7180: fix frame interval in progressive mode Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.6] media: v4l2-async: Fix error handling on steps after finding a match Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.1] media: rkisp1: Fix filter mode register configuration Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Ensure stream_mutex is acquired when dealing with node list Sasha Levin
2026-02-14  0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Return -EPROBE_DEFER if no endpoint is found Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-6.18] media: uvcvideo: Create an ID namespace for streaming output terminals Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Always close firmware stream Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-6.18] media: qcom: camss: Do not enable cpas fast ahb clock for SM8550 VFE lite Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-5.10] media: solo6x10: Check for out of bounds chip_id Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-6.18] drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v4 Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Process ready frames when CMD_STOP sent to Encoder Sasha Levin
2026-02-14  0:59 ` [PATCH AUTOSEL 6.19-5.10] media: pvrusb2: fix URB leak in pvr2_send_request_ex Sasha Levin
2026-02-14  0:59 ` Sasha Levin [this message]

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=20260214010245.3671907-109-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=hverkuil@kernel.org \
    --cc=hverkuil@xs4all.nl \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab+huawei@kernel.org \
    --cc=mchehab@kernel.org \
    --cc=mingo@kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=patches@lists.linux.dev \
    --cc=rongqianfeng@vivo.com \
    --cc=stable@vger.kernel.org \
    --cc=tglx@kernel.org \
    --cc=yelangyan@huaqin.corp-partner.google.com \
    /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