[media] em28xx: fix race on disconnect
This patch closes the race on the device and extension lists at USB disconnect time. Previously, the device was removed from the device list during em28xx_release_resources(), and then passed to the em28xx_close_extension() function so that all extensions could run their fini() operations. However, this left a (brief, theoretical, highly unlikely ;-)) window between these two calls during which a new module could call em28xx_register_extension(). The result would have been that the em28xx_usb_disconnect() function would also have passed the device to the new extension's fini() function, despite never having called the extension's init() function. This patch also restores em28xx_close_extension()'s symmetry with em28xx_init_extension(), and establishes the property that every device in the device list must have been initialised for every extension in the extension list. Signed-off-by: Chris Rankin <rankincj@yahoo.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>hifive-unleashed-5.1
parent
bd829e9d1d
commit
d7222e7d6f
|
@ -2800,9 +2800,9 @@ static void flush_request_modules(struct em28xx *dev)
|
||||||
#endif /* CONFIG_MODULES */
|
#endif /* CONFIG_MODULES */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* em28xx_realease_resources()
|
* em28xx_release_resources()
|
||||||
* unregisters the v4l2,i2c and usb devices
|
* unregisters the v4l2,i2c and usb devices
|
||||||
* called when the device gets disconected or at module unload
|
* called when the device gets disconnected or at module unload
|
||||||
*/
|
*/
|
||||||
void em28xx_release_resources(struct em28xx *dev)
|
void em28xx_release_resources(struct em28xx *dev)
|
||||||
{
|
{
|
||||||
|
@ -2816,8 +2816,6 @@ void em28xx_release_resources(struct em28xx *dev)
|
||||||
|
|
||||||
em28xx_release_analog_resources(dev);
|
em28xx_release_analog_resources(dev);
|
||||||
|
|
||||||
em28xx_remove_from_devlist(dev);
|
|
||||||
|
|
||||||
em28xx_i2c_unregister(dev);
|
em28xx_i2c_unregister(dev);
|
||||||
|
|
||||||
v4l2_device_unregister(&dev->v4l2_dev);
|
v4l2_device_unregister(&dev->v4l2_dev);
|
||||||
|
@ -3255,7 +3253,7 @@ err_no_slot:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* em28xx_usb_disconnect()
|
* em28xx_usb_disconnect()
|
||||||
* called when the device gets diconencted
|
* called when the device gets disconnected
|
||||||
* video device will be unregistered on v4l2_close in case it is still open
|
* video device will be unregistered on v4l2_close in case it is still open
|
||||||
*/
|
*/
|
||||||
static void em28xx_usb_disconnect(struct usb_interface *interface)
|
static void em28xx_usb_disconnect(struct usb_interface *interface)
|
||||||
|
|
|
@ -1183,18 +1183,6 @@ void em28xx_wake_i2c(struct em28xx *dev)
|
||||||
static LIST_HEAD(em28xx_devlist);
|
static LIST_HEAD(em28xx_devlist);
|
||||||
static DEFINE_MUTEX(em28xx_devlist_mutex);
|
static DEFINE_MUTEX(em28xx_devlist_mutex);
|
||||||
|
|
||||||
/*
|
|
||||||
* em28xx_realease_resources()
|
|
||||||
* unregisters the v4l2,i2c and usb devices
|
|
||||||
* called when the device gets disconected or at module unload
|
|
||||||
*/
|
|
||||||
void em28xx_remove_from_devlist(struct em28xx *dev)
|
|
||||||
{
|
|
||||||
mutex_lock(&em28xx_devlist_mutex);
|
|
||||||
list_del(&dev->devlist);
|
|
||||||
mutex_unlock(&em28xx_devlist_mutex);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extension interface
|
* Extension interface
|
||||||
*/
|
*/
|
||||||
|
@ -1245,14 +1233,13 @@ void em28xx_init_extension(struct em28xx *dev)
|
||||||
|
|
||||||
void em28xx_close_extension(struct em28xx *dev)
|
void em28xx_close_extension(struct em28xx *dev)
|
||||||
{
|
{
|
||||||
struct em28xx_ops *ops = NULL;
|
const struct em28xx_ops *ops = NULL;
|
||||||
|
|
||||||
mutex_lock(&em28xx_devlist_mutex);
|
mutex_lock(&em28xx_devlist_mutex);
|
||||||
if (!list_empty(&em28xx_extension_devlist)) {
|
|
||||||
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
|
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
|
||||||
if (ops->fini)
|
if (ops->fini)
|
||||||
ops->fini(dev);
|
ops->fini(dev);
|
||||||
}
|
}
|
||||||
}
|
list_del(&dev->devlist);
|
||||||
mutex_unlock(&em28xx_devlist_mutex);
|
mutex_unlock(&em28xx_devlist_mutex);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue