Skip to content

Commit e2c91d4

Browse files
committed
[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: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160 #1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160 #2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio] #3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] 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: [<ffffffff81933901>] dump_stack+0x85/0xc4 [<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0 [<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0 [<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300 [<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media] [<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media] [<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media] [<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828] [<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media] [<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media] Reviewed-by: Javier Martinez Canillas <[email protected]> Acked-by: Sakari Ailus <[email protected]> Acked-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent ecb7b01 commit e2c91d4

File tree

3 files changed

+22
-39
lines changed

3 files changed

+22
-39
lines changed

drivers/media/media-device.c

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,13 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
9090

9191
id &= ~MEDIA_ENT_ID_FLAG_NEXT;
9292

93-
spin_lock(&mdev->lock);
94-
9593
media_device_for_each_entity(entity, mdev) {
9694
if (((media_entity_id(entity) == id) && !next) ||
9795
((media_entity_id(entity) > id) && next)) {
98-
spin_unlock(&mdev->lock);
9996
return entity;
10097
}
10198
}
10299

103-
spin_unlock(&mdev->lock);
104-
105100
return NULL;
106101
}
107102

@@ -431,6 +426,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
431426
struct media_device *dev = to_media_device(devnode);
432427
long ret;
433428

429+
mutex_lock(&dev->graph_mutex);
434430
switch (cmd) {
435431
case MEDIA_IOC_DEVICE_INFO:
436432
ret = media_device_get_info(dev,
@@ -443,29 +439,24 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
443439
break;
444440

445441
case MEDIA_IOC_ENUM_LINKS:
446-
mutex_lock(&dev->graph_mutex);
447442
ret = media_device_enum_links(dev,
448443
(struct media_links_enum __user *)arg);
449-
mutex_unlock(&dev->graph_mutex);
450444
break;
451445

452446
case MEDIA_IOC_SETUP_LINK:
453-
mutex_lock(&dev->graph_mutex);
454447
ret = media_device_setup_link(dev,
455448
(struct media_link_desc __user *)arg);
456-
mutex_unlock(&dev->graph_mutex);
457449
break;
458450

459451
case MEDIA_IOC_G_TOPOLOGY:
460-
mutex_lock(&dev->graph_mutex);
461452
ret = media_device_get_topology(dev,
462453
(struct media_v2_topology __user *)arg);
463-
mutex_unlock(&dev->graph_mutex);
464454
break;
465455

466456
default:
467457
ret = -ENOIOCTLCMD;
468458
}
459+
mutex_unlock(&dev->graph_mutex);
469460

470461
return ret;
471462
}
@@ -590,12 +581,12 @@ int __must_check media_device_register_entity(struct media_device *mdev,
590581
if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
591582
return -ENOMEM;
592583

593-
spin_lock(&mdev->lock);
584+
mutex_lock(&mdev->graph_mutex);
594585

595586
ret = ida_get_new_above(&mdev->entity_internal_idx, 1,
596587
&entity->internal_idx);
597588
if (ret < 0) {
598-
spin_unlock(&mdev->lock);
589+
mutex_unlock(&mdev->graph_mutex);
599590
return ret;
600591
}
601592

@@ -615,9 +606,6 @@ int __must_check media_device_register_entity(struct media_device *mdev,
615606
(notify)->notify(entity, notify->notify_data);
616607
}
617608

618-
spin_unlock(&mdev->lock);
619-
620-
mutex_lock(&mdev->graph_mutex);
621609
if (mdev->entity_internal_idx_max
622610
>= mdev->pm_count_walk.ent_enum.idx_max) {
623611
struct media_entity_graph new = { .top = 0 };
@@ -680,9 +668,9 @@ void media_device_unregister_entity(struct media_entity *entity)
680668
if (mdev == NULL)
681669
return;
682670

683-
spin_lock(&mdev->lock);
671+
mutex_lock(&mdev->graph_mutex);
684672
__media_device_unregister_entity(entity);
685-
spin_unlock(&mdev->lock);
673+
mutex_unlock(&mdev->graph_mutex);
686674
}
687675
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
688676

@@ -703,7 +691,6 @@ void media_device_init(struct media_device *mdev)
703691
INIT_LIST_HEAD(&mdev->pads);
704692
INIT_LIST_HEAD(&mdev->links);
705693
INIT_LIST_HEAD(&mdev->entity_notify);
706-
spin_lock_init(&mdev->lock);
707694
mutex_init(&mdev->graph_mutex);
708695
ida_init(&mdev->entity_internal_idx);
709696

@@ -752,9 +739,9 @@ EXPORT_SYMBOL_GPL(__media_device_register);
752739
int __must_check media_device_register_entity_notify(struct media_device *mdev,
753740
struct media_entity_notify *nptr)
754741
{
755-
spin_lock(&mdev->lock);
742+
mutex_lock(&mdev->graph_mutex);
756743
list_add_tail(&nptr->list, &mdev->entity_notify);
757-
spin_unlock(&mdev->lock);
744+
mutex_unlock(&mdev->graph_mutex);
758745
return 0;
759746
}
760747
EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
@@ -771,9 +758,9 @@ static void __media_device_unregister_entity_notify(struct media_device *mdev,
771758
void media_device_unregister_entity_notify(struct media_device *mdev,
772759
struct media_entity_notify *nptr)
773760
{
774-
spin_lock(&mdev->lock);
761+
mutex_lock(&mdev->graph_mutex);
775762
__media_device_unregister_entity_notify(mdev, nptr);
776-
spin_unlock(&mdev->lock);
763+
mutex_unlock(&mdev->graph_mutex);
777764
}
778765
EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
779766

@@ -787,11 +774,11 @@ void media_device_unregister(struct media_device *mdev)
787774
if (mdev == NULL)
788775
return;
789776

790-
spin_lock(&mdev->lock);
777+
mutex_lock(&mdev->graph_mutex);
791778

792779
/* Check if mdev was ever registered at all */
793780
if (!media_devnode_is_registered(&mdev->devnode)) {
794-
spin_unlock(&mdev->lock);
781+
mutex_unlock(&mdev->graph_mutex);
795782
return;
796783
}
797784

@@ -811,7 +798,7 @@ void media_device_unregister(struct media_device *mdev)
811798
kfree(intf);
812799
}
813800

814-
spin_unlock(&mdev->lock);
801+
mutex_unlock(&mdev->graph_mutex);
815802

816803
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
817804
media_devnode_unregister(&mdev->devnode);

drivers/media/media-entity.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
219219
entity->pads = pads;
220220

221221
if (mdev)
222-
spin_lock(&mdev->lock);
222+
mutex_lock(&mdev->graph_mutex);
223223

224224
for (i = 0; i < num_pads; i++) {
225225
pads[i].entity = entity;
@@ -230,7 +230,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
230230
}
231231

232232
if (mdev)
233-
spin_unlock(&mdev->lock);
233+
mutex_unlock(&mdev->graph_mutex);
234234

235235
return 0;
236236
}
@@ -747,9 +747,9 @@ void media_entity_remove_links(struct media_entity *entity)
747747
if (mdev == NULL)
748748
return;
749749

750-
spin_lock(&mdev->lock);
750+
mutex_lock(&mdev->graph_mutex);
751751
__media_entity_remove_links(entity);
752-
spin_unlock(&mdev->lock);
752+
mutex_unlock(&mdev->graph_mutex);
753753
}
754754
EXPORT_SYMBOL_GPL(media_entity_remove_links);
755755

@@ -951,9 +951,9 @@ void media_remove_intf_link(struct media_link *link)
951951
if (mdev == NULL)
952952
return;
953953

954-
spin_lock(&mdev->lock);
954+
mutex_lock(&mdev->graph_mutex);
955955
__media_remove_intf_link(link);
956-
spin_unlock(&mdev->lock);
956+
mutex_unlock(&mdev->graph_mutex);
957957
}
958958
EXPORT_SYMBOL_GPL(media_remove_intf_link);
959959

@@ -975,8 +975,8 @@ void media_remove_intf_links(struct media_interface *intf)
975975
if (mdev == NULL)
976976
return;
977977

978-
spin_lock(&mdev->lock);
978+
mutex_lock(&mdev->graph_mutex);
979979
__media_remove_intf_links(intf);
980-
spin_unlock(&mdev->lock);
980+
mutex_unlock(&mdev->graph_mutex);
981981
}
982982
EXPORT_SYMBOL_GPL(media_remove_intf_links);

include/media/media-device.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
#include <linux/list.h>
2727
#include <linux/mutex.h>
28-
#include <linux/spinlock.h>
2928

3029
#include <media/media-devnode.h>
3130
#include <media/media-entity.h>
@@ -304,8 +303,7 @@ struct media_entity_notify {
304303
* @pads: List of registered pads
305304
* @links: List of registered links
306305
* @entity_notify: List of registered entity_notify callbacks
307-
* @lock: Entities list lock
308-
* @graph_mutex: Entities graph operation lock
306+
* @graph_mutex: Protects access to struct media_device data
309307
* @pm_count_walk: Graph walk for power state walk. Access serialised using
310308
* graph_mutex.
311309
*
@@ -371,8 +369,6 @@ struct media_device {
371369
/* notify callback list invoked when a new entity is registered */
372370
struct list_head entity_notify;
373371

374-
/* Protects the graph objects creation/removal */
375-
spinlock_t lock;
376372
/* Serializes graph operations. */
377373
struct mutex graph_mutex;
378374
struct media_entity_graph pm_count_walk;

0 commit comments

Comments
 (0)