From: Frank Li <Frank.li@oss.nxp.com>
To: Xu Yang <xu.yang_2@oss.nxp.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Kai Aizen <kai.aizen.dev@gmail.com>,
Michael Grzeschik <mgr@kernel.org>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
imx@lists.linux.dev, Xu Yang <xu.yang_2@nxp.com>
Subject: Re: [PATCH 2/2] usb: gadget: uvc: refactor video cleanup into uvcg_video_deinit()
Date: Fri, 21 Aug 2026 09:36:31 -0500 [thread overview]
Message-ID: <aohib0yXT92apzfl@SMW015318> (raw)
In-Reply-To: <20260821-usb-uvc-fixes-v1-2-80e6e279523d@nxp.com>
On Fri, Aug 21, 2026 at 04:22:37PM +0800, Xu Yang wrote:
> From: Xu Yang <xu.yang_2@nxp.com>
>
> kthread_destroy_worker() was never called during unbind, leaving the
> UVCG kthread running after the gadget function is unbound. Also, if
> uvcg_video_init() or uvc_register_video() fails during bind, async_wq
> and kworker were not cleaned up, causing resource leaks.
>
> Both issues require the same teardown sequence: cancel the pending work,
> destroy the kworker, and destroy the workqueue. Consolidate this logic
> into a new uvcg_video_deinit() helper and call it from both
> uvc_function_unbind() and the v4l2_error path in uvc_function_bind().
>
> In uvc_function_unbind(), uvcg_video_deinit() is placed after
> video_unregister_device() to fix the ordering. Without this ordering,
> tearing down the workers before unregistering the V4L2 device could lead
> to use-after-free on video device resources still accessed by those
> workers.
>
> Fixes: f0bbfbd16b3b ("usb: gadget: uvc: rework to enqueue in pump worker from encoded queue")
> Assisted-by: Claude:claude-sonnet-4.6
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/usb/gadget/function/f_uvc.c | 7 ++-----
> drivers/usb/gadget/function/uvc_video.c | 15 +++++++++++++++
> drivers/usb/gadget/function/uvc_video.h | 1 +
> 3 files changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
> index a4fb2790f4ff..fa2f9d0e4ce0 100644
> --- a/drivers/usb/gadget/function/f_uvc.c
> +++ b/drivers/usb/gadget/function/f_uvc.c
> @@ -879,6 +879,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
> return 0;
>
> v4l2_error:
> + uvcg_video_deinit(&uvc->video);
> v4l2_device_unregister(&uvc->v4l2_dev);
> error:
> if (uvc->control_req) {
> @@ -1028,11 +1029,6 @@ static void uvc_function_unbind(struct usb_configuration *c,
> connected = uvc->func_connected;
> }
>
> - kthread_cancel_work_sync(&video->hw_submit);
> -
> - if (video->async_wq)
> - destroy_workqueue(video->async_wq);
> -
> /*
> * If we know we're connected via v4l2, then there should be a cleanup
> * of the device from userspace either via UVC_EVENT_DISCONNECT or
> @@ -1048,6 +1044,7 @@ static void uvc_function_unbind(struct usb_configuration *c,
>
> device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
> video_unregister_device(&uvc->vdev);
> + uvcg_video_deinit(video);
> v4l2_device_unregister(&uvc->v4l2_dev);
>
> scoped_guard(mutex, &uvc->lock)
> diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
> index 9ba09118bb74..002afca9141e 100644
> --- a/drivers/usb/gadget/function/uvc_video.c
> +++ b/drivers/usb/gadget/function/uvc_video.c
> @@ -841,3 +841,18 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
> return uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
> V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex);
> }
> +
> +void uvcg_video_deinit(struct uvc_video *video)
> +{
> + kthread_cancel_work_sync(&video->hw_submit);
> +
> + if (!IS_ERR_OR_NULL(video->kworker)) {
> + kthread_destroy_worker(video->kworker);
> + video->kworker = NULL;
> + }
> +
> + if (video->async_wq) {
> + destroy_workqueue(video->async_wq);
> + video->async_wq = NULL;
> + }
> +}
> diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h
> index 8ef6259741f1..6c5481f107f9 100644
> --- a/drivers/usb/gadget/function/uvc_video.h
> +++ b/drivers/usb/gadget/function/uvc_video.h
> @@ -18,5 +18,6 @@ int uvcg_video_enable(struct uvc_video *video);
> int uvcg_video_disable(struct uvc_video *video);
>
> int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc);
> +void uvcg_video_deinit(struct uvc_video *video);
>
> #endif /* __UVC_VIDEO_H__ */
>
> --
> 2.34.1
>
>
prev parent reply other threads:[~2026-08-21 14:36 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 8:22 [PATCH 0/2] usb: gadget: uvc: fix resource leak on video->async_wq and video->kworker Xu Yang
2026-08-21 8:22 ` [PATCH 1/2] usb: gadget: uvc: replace mutex lock/unlock with scoped_guard in uvc_function_bind() Xu Yang
2026-08-21 8:35 ` sashiko-bot
2026-08-21 14:36 ` Frank Li
2026-08-21 8:22 ` [PATCH 2/2] usb: gadget: uvc: refactor video cleanup into uvcg_video_deinit() Xu Yang
2026-08-21 8:32 ` sashiko-bot
2026-08-21 14:36 ` Frank Li [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=aohib0yXT92apzfl@SMW015318 \
--to=frank.li@oss.nxp.com \
--cc=gregkh@linuxfoundation.org \
--cc=imx@lists.linux.dev \
--cc=kai.aizen.dev@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mgr@kernel.org \
--cc=xu.yang_2@nxp.com \
--cc=xu.yang_2@oss.nxp.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.