On Wed May 13 08:42:44 2026 +0300, Valery Borovsky wrote:
> pwc_isoc_init() submits its isochronous URBs with
> usb_submit_urb(.., GFP_KERNEL) in a loop. After the first URB is
> submitted, its completion handler pwc_isoc_handler() can run on another
> CPU before the loop finishes:
> 
>   start_streaming()
>     pwc_isoc_init()
>       usb_submit_urb(urbs[0], GFP_KERNEL)
>                                   pwc_isoc_handler(urbs[0])
>                                     pdev->fill_buf =
>                                       pwc_get_next_fill_buf(pdev)
>       usb_submit_urb(urbs[i>0], ..)  -> fails
>       pwc_isoc_cleanup(pdev)           /* kills URBs */
>       return ret;
>     pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED)
> 
> pwc_get_next_fill_buf() detaches a buffer from pdev->queued_bufs and
> stores it in pdev->fill_buf. The error path in start_streaming() only
> drains pdev->queued_bufs, so the buffer parked in pdev->fill_buf is
> leaked. vb2_start_streaming() then triggers
> WARN_ON(owned_by_drv_count).
> 
> stop_streaming() already handles this since commit 80b0963e1698
> ("[media] pwc: fix WARN_ON"), which added the fill_buf drain in the
> teardown path but not in the start_streaming() error path. Mirror that
> handling on failure so start_streaming() returns with no buffer owned
> by the driver.
> 
> Issue identified by automated review of the INV-003 series at
> https://sashiko.dev/
> 
> Fixes: 885fe18f5542 ("[media] pwc: Replace private buffer management code 
> with videobuf2")
> Cc: [email protected]
> Signed-off-by: Valery Borovsky <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/usb/pwc/pwc-if.c | 5 +++++
 1 file changed, 5 insertions(+)

---

diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 59b99ac8fcb6..e2884b04d952 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -730,6 +730,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned 
int count)
                pwc_camera_power(pdev, 0);
                /* And cleanup any queued bufs!! */
                pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
+               if (pdev->fill_buf) {
+                       vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf,
+                                       VB2_BUF_STATE_QUEUED);
+                       pdev->fill_buf = NULL;
+               }
        }
        mutex_unlock(&pdev->v4l2_lock);
 
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to