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: 9d15cd958c
("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>
This commit is contained in:
parent
6c0e931c74
commit
f9ffcb0a21
1 changed files with 2 additions and 9 deletions
|
@ -1871,13 +1871,6 @@ static void uvc_unregister_video(struct uvc_device *dev)
|
||||||
{
|
{
|
||||||
struct uvc_streaming *stream;
|
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) {
|
list_for_each_entry(stream, &dev->streams, list) {
|
||||||
if (!video_is_registered(&stream->vdev))
|
if (!video_is_registered(&stream->vdev))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1887,8 +1880,6 @@ static void uvc_unregister_video(struct uvc_device *dev)
|
||||||
|
|
||||||
uvc_debugfs_cleanup_stream(stream);
|
uvc_debugfs_cleanup_stream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_put(&dev->ref, uvc_delete);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int uvc_register_video_device(struct uvc_device *dev,
|
int uvc_register_video_device(struct uvc_device *dev,
|
||||||
|
@ -2184,6 +2175,7 @@ static int uvc_probe(struct usb_interface *intf,
|
||||||
|
|
||||||
error:
|
error:
|
||||||
uvc_unregister_video(dev);
|
uvc_unregister_video(dev);
|
||||||
|
kref_put(&dev->ref, uvc_delete);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2201,6 +2193,7 @@ static void uvc_disconnect(struct usb_interface *intf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uvc_unregister_video(dev);
|
uvc_unregister_video(dev);
|
||||||
|
kref_put(&dev->ref, uvc_delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
|
static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
|
|
Loading…
Reference in a new issue