summaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorPhilipp Zabel <philipp.zabel@gmail.com>2018-05-21 12:24:58 +0200
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-05-28 22:49:47 +0200
commitf9ffcb0a21e1fa8e64d09ed613d884e054ae8191 (patch)
tree3056d7b1b874e007d756dd264691faba460530f1 /drivers/media
parentmedia: gspca_zc3xx: Enable short exposure times for OV7648 (diff)
downloadlinux-f9ffcb0a21e1fa8e64d09ed613d884e054ae8191.tar.xz
linux-f9ffcb0a21e1fa8e64d09ed613d884e054ae8191.zip
media: uvcvideo: Fix driver reference counting
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>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c11
1 files changed, 2 insertions, 9 deletions
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 2469b49b2b30..8e138201330f 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -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)