[media] media-device: better lock media_device_unregister()
If media_device_unregister() is called by two different drivers, a race condition may happen, as the check if the device is not registered is not protected. Move the spin_lock() to happen earlier in the function, in order to prevent such race condition. Reported-by: Shuah Khan <shuahkh@osg.samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
@@ -573,18 +573,13 @@ EXPORT_SYMBOL_GPL(media_device_register_entity);
|
|||||||
* If the entity has never been registered this function will return
|
* If the entity has never been registered this function will return
|
||||||
* immediately.
|
* immediately.
|
||||||
*/
|
*/
|
||||||
void media_device_unregister_entity(struct media_entity *entity)
|
static void __media_device_unregister_entity(struct media_entity *entity)
|
||||||
{
|
{
|
||||||
struct media_device *mdev = entity->graph_obj.mdev;
|
struct media_device *mdev = entity->graph_obj.mdev;
|
||||||
struct media_link *link, *tmp;
|
struct media_link *link, *tmp;
|
||||||
struct media_interface *intf;
|
struct media_interface *intf;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (mdev == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
spin_lock(&mdev->lock);
|
|
||||||
|
|
||||||
/* Remove all interface links pointing to this entity */
|
/* Remove all interface links pointing to this entity */
|
||||||
list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
|
list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
|
||||||
list_for_each_entry_safe(link, tmp, &intf->links, list) {
|
list_for_each_entry_safe(link, tmp, &intf->links, list) {
|
||||||
@@ -603,11 +598,23 @@ void media_device_unregister_entity(struct media_entity *entity)
|
|||||||
/* Remove the entity */
|
/* Remove the entity */
|
||||||
media_gobj_destroy(&entity->graph_obj);
|
media_gobj_destroy(&entity->graph_obj);
|
||||||
|
|
||||||
spin_unlock(&mdev->lock);
|
|
||||||
entity->graph_obj.mdev = NULL;
|
entity->graph_obj.mdev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void media_device_unregister_entity(struct media_entity *entity)
|
||||||
|
{
|
||||||
|
struct media_device *mdev = entity->graph_obj.mdev;
|
||||||
|
|
||||||
|
if (mdev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock(&mdev->lock);
|
||||||
|
__media_device_unregister_entity(entity);
|
||||||
|
spin_unlock(&mdev->lock);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
|
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* media_device_register - register a media device
|
* media_device_register - register a media device
|
||||||
* @mdev: The media device
|
* @mdev: The media device
|
||||||
@@ -666,22 +673,29 @@ void media_device_unregister(struct media_device *mdev)
|
|||||||
struct media_entity *next;
|
struct media_entity *next;
|
||||||
struct media_interface *intf, *tmp_intf;
|
struct media_interface *intf, *tmp_intf;
|
||||||
|
|
||||||
/* Check if mdev was ever registered at all */
|
if (mdev == NULL)
|
||||||
if (!media_devnode_is_registered(&mdev->devnode))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
spin_lock(&mdev->lock);
|
||||||
|
|
||||||
|
/* Check if mdev was ever registered at all */
|
||||||
|
if (!media_devnode_is_registered(&mdev->devnode)) {
|
||||||
|
spin_unlock(&mdev->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove all entities from the media device */
|
/* Remove all entities from the media device */
|
||||||
list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
|
list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
|
||||||
media_device_unregister_entity(entity);
|
__media_device_unregister_entity(entity);
|
||||||
|
|
||||||
/* Remove all interfaces from the media device */
|
/* Remove all interfaces from the media device */
|
||||||
spin_lock(&mdev->lock);
|
|
||||||
list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
|
list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
|
||||||
graph_obj.list) {
|
graph_obj.list) {
|
||||||
__media_remove_intf_links(intf);
|
__media_remove_intf_links(intf);
|
||||||
media_gobj_destroy(&intf->graph_obj);
|
media_gobj_destroy(&intf->graph_obj);
|
||||||
kfree(intf);
|
kfree(intf);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&mdev->lock);
|
spin_unlock(&mdev->lock);
|
||||||
|
|
||||||
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
|
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
|
||||||
|
Reference in New Issue
Block a user