aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-12-15 08:36:51 -0200
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2016-01-11 12:19:15 -0200
commit821ed3662913faca0653c201fa9e36fbab81f17c (patch)
treec43c57c89f2be2b72dee12183172af907436a999
parentb2ed8af910a436e12038f8ec8ca6c039f43767a4 (diff)
downloadlinux-821ed3662913faca0653c201fa9e36fbab81f17c.tar.gz
[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>
-rw-r--r--drivers/media/media-device.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 1222fa642ad843..189c2ba8c3d353 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);