diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-12-15 08:36:51 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2016-01-11 12:19:15 -0200 |
commit | 821ed3662913faca0653c201fa9e36fbab81f17c (patch) | |
tree | c43c57c89f2be2b72dee12183172af907436a999 /drivers/media | |
parent | b2ed8af910a436e12038f8ec8ca6c039f43767a4 (diff) | |
download | linux-821ed3662913faca0653c201fa9e36fbab81f17c.tar.bz2 |
[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>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/media-device.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 1222fa642ad8..189c2ba8c3d3 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -573,18 +573,13 @@ EXPORT_SYMBOL_GPL(media_device_register_entity); * If the entity has never been registered this function will return * 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_link *link, *tmp; struct media_interface *intf; unsigned int i; - if (mdev == NULL) - return; - - spin_lock(&mdev->lock); - /* Remove all interface links pointing to this entity */ list_for_each_entry(intf, &mdev->interfaces, graph_obj.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 */ media_gobj_destroy(&entity->graph_obj); - spin_unlock(&mdev->lock); 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); + /** * media_device_register - register a media device * @mdev: The media device @@ -666,22 +673,29 @@ void media_device_unregister(struct media_device *mdev) struct media_entity *next; struct media_interface *intf, *tmp_intf; + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(&mdev->devnode)) + if (!media_devnode_is_registered(&mdev->devnode)) { + spin_unlock(&mdev->lock); return; + } /* Remove all entities from the media device */ 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 */ - spin_lock(&mdev->lock); list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, graph_obj.list) { __media_remove_intf_links(intf); media_gobj_destroy(&intf->graph_obj); kfree(intf); } + spin_unlock(&mdev->lock); device_remove_file(&mdev->devnode.dev, &dev_attr_model); |