]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
media: uvcvideo: Fix driver reference counting
authorPhilipp Zabel <philipp.zabel@gmail.com>
Mon, 21 May 2018 10:24:58 +0000 (06:24 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 28 May 2018 20:49:47 +0000 (16:49 -0400)
kref_init initializes the reference count to 1, not 0. This additional
reference is never released since the conversion to reference counters.
As a result, uvc_delete is not called anymore when UVC cameras are
disconnected.
Fix this by adding an additional kref_put in uvc_disconnect and in the
probe error path. This also allows to remove the temporary additional
reference in uvc_unregister_video.

Fixes: 9d15cd958c17 ("media: uvcvideo: Convert from using an atomic variable to a reference count")
Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/usb/uvc/uvc_driver.c

index 2469b49b2b30f313ff80dd8984a7d544bd376deb..8e138201330fc166cd6cd0428023baaed8aca818 100644 (file)
@@ -1871,13 +1871,6 @@ static void uvc_unregister_video(struct uvc_device *dev)
 {
        struct uvc_streaming *stream;
 
-       /* Unregistering all video devices might result in uvc_delete() being
-        * called from inside the loop if there's no open file handle. To avoid
-        * that, increment the refcount before iterating over the streams and
-        * decrement it when done.
-        */
-       kref_get(&dev->ref);
-
        list_for_each_entry(stream, &dev->streams, list) {
                if (!video_is_registered(&stream->vdev))
                        continue;
@@ -1887,8 +1880,6 @@ static void uvc_unregister_video(struct uvc_device *dev)
 
                uvc_debugfs_cleanup_stream(stream);
        }
-
-       kref_put(&dev->ref, uvc_delete);
 }
 
 int uvc_register_video_device(struct uvc_device *dev,
@@ -2184,6 +2175,7 @@ static int uvc_probe(struct usb_interface *intf,
 
 error:
        uvc_unregister_video(dev);
+       kref_put(&dev->ref, uvc_delete);
        return -ENODEV;
 }
 
@@ -2201,6 +2193,7 @@ static void uvc_disconnect(struct usb_interface *intf)
                return;
 
        uvc_unregister_video(dev);
+       kref_put(&dev->ref, uvc_delete);
 }
 
 static int uvc_suspend(struct usb_interface *intf, pm_message_t message)