[PATCH] media: gspca: don't complete buffers before streaming has started
From: 25031212351
Date: Fri Oct 16 2026 - 10:02:49 EST
From: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
gspca enables the data transfers before it knows whether start_streaming()
will succeed: gspca_init_transfer() sets gspca_dev->streaming before the
URBs are submitted, so an URB that has already been submitted can complete
and gspca_frame_add() can hand its buffer to videobuf2 while the remaining
URBs are still being submitted.
When one of those submissions fails, gspca_start_streaming() returns the
buffers that are still queued to vb2 in QUEUED state, but the buffer that
has already been completed is no longer on the driver's queue, and
vb2_buffer_done() cannot take it back (it only accepts active buffers).
vb2_start_streaming() then warns because the driver left a buffer on the
done list although it failed to start:
------------[ cut here ]------------
WARNING: drivers/media/common/videobuf2/videobuf2-core.c:1821 at vb2_start_streaming+0x312/0x680
...
Call Trace:
<TASK>
vb2_core_streamon+0x285/0x470
__vb2_init_fileio+0xdc1/0x1120
__vb2_perform_fileio+0xa7a/0x15e0
vb2_fop_read+0x219/0x3e0
v4l2_read+0x1fc/0x320
vfs_read+0x1d9/0x980
ksys_read+0x111/0x210
...
gspca_main: set alt 0 err -19
gspca_main: usb_submit_urb alt 1 err -2
This was observed on a camera whose USB configuration was changed from
userspace while a read() was starting the stream: the endpoint is removed,
so usb_submit_urb() fails with -ENOENT, and the driver is unbound.
Complete buffers only once streaming has really started, which is what
vb2_is_streaming() reports, so that a failing start_streaming() always
leaves the done list empty. Frames that arrive before that are dropped,
just like frames that arrive when no buffer is queued; this costs at most
one frame at the beginning of a stream.
Fixes: 1f5965c4dfd7 ("media: gspca: convert to vb2")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Bin Yu <byu@xxxxxxxxxxxxx>
Signed-off-by: Bin Yu <byu@xxxxxxxxxxxxx>
Co-developed-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
---
drivers/media/usb/gspca/gspca.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 594d73e50b9f..ffaf77af9079 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -392,8 +392,15 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
spin_unlock_irqrestore(&gspca_dev->qlock, flags);
if (packet_type == FIRST_PACKET) {
- /* if there is no queued buffer, discard the whole frame */
- if (!buf) {
+ /*
+ * If there is no queued buffer, discard the whole frame.
+ * Frames are also discarded while streaming has not been
+ * started successfully yet: the transfers can already be
+ * running at that point, but buffers must not be handed to
+ * vb2 as long as start_streaming() can still fail, since a
+ * completed buffer cannot be taken back.
+ */
+ if (!buf || !vb2_is_streaming(&gspca_dev->queue)) {
gspca_dev->last_packet_type = DISCARD_PACKET;
gspca_dev->sequence++;
return;
--
2.34.1