All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Ricardo Ribalda <ribalda@chromium.org>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>,
	Guenter Roeck <linux@roeck-us.net>,
	Tomasz Figa <tfiga@chromium.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Hans Verkuil <hverkuil-cisco@xs4all.nl>,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	Sean Paul <seanpaul@chromium.org>,
	Sakari Ailus <sakari.ailus@linux.intel.com>
Subject: Re: [PATCH v5 3/3] media: uvcvideo: Do not use usb_* functions after .disconnect
Date: Fri, 22 Mar 2024 16:19:02 +0200	[thread overview]
Message-ID: <20240322141902.GV18799@pendragon.ideasonboard.com> (raw)
In-Reply-To: <CANiDSCunxALoBJg-u_s=A1Zi-NF3SaNRFhv3=2jTx0oeAPrCZw@mail.gmail.com>

Hi Ricardo,

On Wed, Nov 22, 2023 at 03:59:10PM +0100, Ricardo Ribalda wrote:
> On Wed, 22 Nov 2023 at 14:33, Laurent Pinchart wrote:
> > On Wed, Nov 22, 2023 at 11:45:49AM +0000, Ricardo Ribalda wrote:
> > > usb drivers should not call to any I/O function after the
> > > .disconnect() callback has been triggered.
> > > https://www.kernel.org/doc/html/latest/driver-api/usb/callbacks.html#the-disconnect-callback
> > >
> > > If an application is receiving frames form a camera and the device is
> > > disconnected: the device will call close() after the usb .disconnect()
> > > callback has been called. The streamoff path will call usb_set_interface
> > > or usb_clear_halt, which is not allowed.
> > >
> > > This patch only solves the calls to close() *after* .disconnect() is
> > > being called.
> > >
> > > Trace:
> > > [ 1065.389723] drivers/media/usb/uvc/uvc_driver.c:2248 uvc_disconnect enter
> > > [ 1065.390160] drivers/media/usb/uvc/uvc_driver.c:2264 uvc_disconnect exit
> > > [ 1065.433956] drivers/media/usb/uvc/uvc_v4l2.c:659 uvc_v4l2_release enter
> > > [ 1065.433973] drivers/media/usb/uvc/uvc_video.c:2274 uvc_video_stop_streaming enter
> > > [ 1065.434560] drivers/media/usb/uvc/uvc_video.c:2285 uvc_video_stop_streaming exit
> > > [ 1065.435154] drivers/media/usb/uvc/uvc_v4l2.c:680 uvc_v4l2_release exit
> > > [ 1065.435188] drivers/media/usb/uvc/uvc_driver.c:2248 uvc_disconnect enter
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > >  drivers/media/usb/uvc/uvc_driver.c |  2 ++
> > >  drivers/media/usb/uvc/uvc_video.c  | 45 ++++++++++++++++++++++++--------------
> > >  drivers/media/usb/uvc/uvcvideo.h   |  2 ++
> > >  3 files changed, 32 insertions(+), 17 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> > > index d5dbf2644272..d78640d422f4 100644
> > > --- a/drivers/media/usb/uvc/uvc_driver.c
> > > +++ b/drivers/media/usb/uvc/uvc_driver.c
> > > @@ -2266,6 +2266,8 @@ static void uvc_disconnect(struct usb_interface *intf)
> > >               return;
> > >
> > >       uvc_unregister_video(dev);
> > > +     /* Barrier needed to pair with uvc_video_stop_streaming(). */
> > > +     smp_store_release(&dev->disconnected, true);
> >
> > I can't think this would be such a hot path that we really need barriers
> > in the driver.
> 
> Using the same variable from two contexts without any sync feels weird.
> 
> Your concern is that there will be a big penalty by using the
> barriers? This is only used in stop_streaming and the shutdown path.

What I meant is that lockless concurrency is much harder to get right
than locked concurrency. Unless there's an important reason not to use
lock (which would I think need to be related to performance, and I don't
see that being an issue here), I think using locks will be less
error-prone and more maintainable. That's the KISS approach to
concurrency (even if it doesn't directly address lockless concurrency, I
like the approach advocated by Sima in
https://blog.ffwll.ch/2022/07/locking-engineering.html).

> > >       kref_put(&dev->ref, uvc_delete);
> > >  }
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> > > index 28dde08ec6c5..f5ef375088de 100644
> > > --- a/drivers/media/usb/uvc/uvc_video.c
> > > +++ b/drivers/media/usb/uvc/uvc_video.c
> > > @@ -2243,28 +2243,39 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
> > >       return ret;
> > >  }
> > >
> > > -void uvc_video_stop_streaming(struct uvc_streaming *stream)
> > > +static void uvc_video_halt(struct uvc_streaming *stream)
> > >  {
> > > -     uvc_video_stop_transfer(stream, 1);
> > > +     unsigned int epnum;
> > > +     unsigned int pipe;
> > > +     unsigned int dir;
> > >
> > >       if (stream->intf->num_altsetting > 1) {
> > >               usb_set_interface(stream->dev->udev, stream->intfnum, 0);
> > > -     } else {
> > > -             /*
> > > -              * UVC doesn't specify how to inform a bulk-based device
> > > -              * when the video stream is stopped. Windows sends a
> > > -              * CLEAR_FEATURE(HALT) request to the video streaming
> > > -              * bulk endpoint, mimic the same behaviour.
> > > -              */
> > > -             unsigned int epnum = stream->header.bEndpointAddress
> > > -                                & USB_ENDPOINT_NUMBER_MASK;
> > > -             unsigned int dir = stream->header.bEndpointAddress
> > > -                              & USB_ENDPOINT_DIR_MASK;
> > > -             unsigned int pipe;
> > > -
> > > -             pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
> > > -             usb_clear_halt(stream->dev->udev, pipe);
> > > +             return;
> > >       }
> > >
> > > +     /*
> > > +      * UVC doesn't specify how to inform a bulk-based device
> > > +      * when the video stream is stopped. Windows sends a
> > > +      * CLEAR_FEATURE(HALT) request to the video streaming
> > > +      * bulk endpoint, mimic the same behaviour.
> > > +      */
> > > +     epnum = stream->header.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
> > > +     dir = stream->header.bEndpointAddress & USB_ENDPOINT_DIR_MASK;
> > > +     pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
> > > +     usb_clear_halt(stream->dev->udev, pipe);
> > > +}
> > > +
> > > +void uvc_video_stop_streaming(struct uvc_streaming *stream)
> > > +{
> > > +     uvc_video_stop_transfer(stream, 1);
> > > +
> > > +     /*
> > > +      * Barrier needed to pair with uvc_disconnect().
> > > +      * We cannot call usb_* functions on a disconnected USB device.
> > > +      */
> > > +     if (!smp_load_acquire(&stream->dev->disconnected))
> > > +             uvc_video_halt(stream);
> > > +
> > >       uvc_video_clock_cleanup(stream);
> > >  }
> > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > index ba8f8c1f2c83..5b1a3643de05 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -559,6 +559,8 @@ struct uvc_device {
> > >       unsigned int users;
> > >       atomic_t nmappings;
> > >
> > > +     bool disconnected;
> > > +
> > >       /* Video control interface */
> > >  #ifdef CONFIG_MEDIA_CONTROLLER
> > >       struct media_device mdev;
> > >

-- 
Regards,

Laurent Pinchart

  reply	other threads:[~2024-03-22 14:19 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-22 11:45 [PATCH v5 0/3] uvcvideo: Attempt N to land UVC race conditions fixes Ricardo Ribalda
2023-11-22 11:45 ` [PATCH v5 1/3] media: uvcvideo: Lock video streams and queues while unregistering Ricardo Ribalda
2024-03-21 15:47   ` Hans Verkuil
2024-03-25 16:37     ` Ricardo Ribalda
2023-11-22 11:45 ` [PATCH v5 2/3] media: uvcvideo: Always use uvc_status_stop() Ricardo Ribalda
2023-11-22 13:32   ` Laurent Pinchart
2023-11-22 11:45 ` [PATCH v5 3/3] media: uvcvideo: Do not use usb_* functions after .disconnect Ricardo Ribalda
2023-11-22 13:33   ` Laurent Pinchart
2023-11-22 14:59     ` Ricardo Ribalda
2024-03-22 14:19       ` Laurent Pinchart [this message]
2024-03-22 14:31         ` Ricardo Ribalda

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=20240322141902.GV18799@pendragon.ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=hverkuil-cisco@xs4all.nl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mchehab@kernel.org \
    --cc=ribalda@chromium.org \
    --cc=sakari.ailus@linux.intel.com \
    --cc=seanpaul@chromium.org \
    --cc=stern@rowland.harvard.edu \
    --cc=tfiga@chromium.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 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.