From e2c91d4d78ee3a69ad634bc7ef90688704baab9d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Apr 2016 10:55:24 -0300 Subject: [media] media-device: get rid of the spinlock Right now, the lock schema for media_device struct is messy, since sometimes, it is protected via a spin lock, while, for media graph traversal, it is protected by a mutex. Solve this conflict by always using a mutex. As a side effect, this prevents a bug when the media notifiers is called at atomic context, while running the notifier callback: BUG: sleeping function called from invalid context at mm/slub.c:1289 in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe 4 locks held by modprobe/3479: #0: (&dev->mutex){......}, at: [] __driver_attach+0xa3/0x160 #1: (&dev->mutex){......}, at: [] __driver_attach+0xb1/0x160 #2: (register_mutex#5){+.+.+.}, at: [] usb_audio_probe+0x257/0x1c90 [snd_usb_audio] #3: (&(&mdev->lock)->rlock){+.+.+.}, at: [] media_device_register_entity+0x1cb/0x700 [media] CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000 ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000 ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5 Call Trace: [] dump_stack+0x85/0xc4 [] ___might_sleep+0x245/0x3a0 [] __might_sleep+0x95/0x1a0 [] kmem_cache_alloc_trace+0x20e/0x300 [] ? media_add_link+0x4d/0x140 [media] [] media_add_link+0x4d/0x140 [media] [] media_create_pad_link+0xa1/0x600 [media] [] au0828_media_graph_notify+0x173/0x360 [au0828] [] ? media_gobj_create+0x1ba/0x480 [media] [] media_device_register_entity+0x3ab/0x700 [media] Reviewed-by: Javier Martinez Canillas Acked-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 39 +++++++++++++-------------------------- drivers/media/media-entity.c | 16 ++++++++-------- 2 files changed, 21 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 6e43c95..898a3cf 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -90,18 +90,13 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) id &= ~MEDIA_ENT_ID_FLAG_NEXT; - spin_lock(&mdev->lock); - media_device_for_each_entity(entity, mdev) { if (((media_entity_id(entity) == id) && !next) || ((media_entity_id(entity) > id) && next)) { - spin_unlock(&mdev->lock); return entity; } } - spin_unlock(&mdev->lock); - return NULL; } @@ -431,6 +426,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, struct media_device *dev = to_media_device(devnode); long ret; + mutex_lock(&dev->graph_mutex); switch (cmd) { case MEDIA_IOC_DEVICE_INFO: ret = media_device_get_info(dev, @@ -443,29 +439,24 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, break; case MEDIA_IOC_ENUM_LINKS: - mutex_lock(&dev->graph_mutex); ret = media_device_enum_links(dev, (struct media_links_enum __user *)arg); - mutex_unlock(&dev->graph_mutex); break; case MEDIA_IOC_SETUP_LINK: - mutex_lock(&dev->graph_mutex); ret = media_device_setup_link(dev, (struct media_link_desc __user *)arg); - mutex_unlock(&dev->graph_mutex); break; case MEDIA_IOC_G_TOPOLOGY: - mutex_lock(&dev->graph_mutex); ret = media_device_get_topology(dev, (struct media_v2_topology __user *)arg); - mutex_unlock(&dev->graph_mutex); break; default: ret = -ENOIOCTLCMD; } + mutex_unlock(&dev->graph_mutex); return ret; } @@ -590,12 +581,12 @@ int __must_check media_device_register_entity(struct media_device *mdev, if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) return -ENOMEM; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); ret = ida_get_new_above(&mdev->entity_internal_idx, 1, &entity->internal_idx); if (ret < 0) { - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); return ret; } @@ -615,9 +606,6 @@ int __must_check media_device_register_entity(struct media_device *mdev, (notify)->notify(entity, notify->notify_data); } - spin_unlock(&mdev->lock); - - mutex_lock(&mdev->graph_mutex); if (mdev->entity_internal_idx_max >= mdev->pm_count_walk.ent_enum.idx_max) { struct media_entity_graph new = { .top = 0 }; @@ -680,9 +668,9 @@ void media_device_unregister_entity(struct media_entity *entity) if (mdev == NULL) return; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); __media_device_unregister_entity(entity); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_device_unregister_entity); @@ -703,7 +691,6 @@ void media_device_init(struct media_device *mdev) INIT_LIST_HEAD(&mdev->pads); INIT_LIST_HEAD(&mdev->links); INIT_LIST_HEAD(&mdev->entity_notify); - spin_lock_init(&mdev->lock); mutex_init(&mdev->graph_mutex); ida_init(&mdev->entity_internal_idx); @@ -752,9 +739,9 @@ EXPORT_SYMBOL_GPL(__media_device_register); int __must_check media_device_register_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr) { - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); list_add_tail(&nptr->list, &mdev->entity_notify); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); return 0; } EXPORT_SYMBOL_GPL(media_device_register_entity_notify); @@ -771,9 +758,9 @@ static void __media_device_unregister_entity_notify(struct media_device *mdev, void media_device_unregister_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr) { - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); __media_device_unregister_entity_notify(mdev, nptr); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); @@ -787,11 +774,11 @@ void media_device_unregister(struct media_device *mdev) if (mdev == NULL) return; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); /* Check if mdev was ever registered at all */ if (!media_devnode_is_registered(&mdev->devnode)) { - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); return; } @@ -811,7 +798,7 @@ void media_device_unregister(struct media_device *mdev) kfree(intf); } - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); device_remove_file(&mdev->devnode.dev, &dev_attr_model); media_devnode_unregister(&mdev->devnode); diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index e95070b..c53c1d5 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -219,7 +219,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, entity->pads = pads; if (mdev) - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); for (i = 0; i < num_pads; i++) { pads[i].entity = entity; @@ -230,7 +230,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, } if (mdev) - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); return 0; } @@ -747,9 +747,9 @@ void media_entity_remove_links(struct media_entity *entity) if (mdev == NULL) return; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); __media_entity_remove_links(entity); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_entity_remove_links); @@ -951,9 +951,9 @@ void media_remove_intf_link(struct media_link *link) if (mdev == NULL) return; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); __media_remove_intf_link(link); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_remove_intf_link); @@ -975,8 +975,8 @@ void media_remove_intf_links(struct media_interface *intf) if (mdev == NULL) return; - spin_lock(&mdev->lock); + mutex_lock(&mdev->graph_mutex); __media_remove_intf_links(intf); - spin_unlock(&mdev->lock); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_remove_intf_links); -- cgit v1.1