Re: [PATCH 1/2] [media] media-device: get rid of the spinlock

2016-04-15 Thread Hans Verkuil
On 04/06/2016 03:55 PM, Mauro Carvalho Chehab wrote:
> 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
>   8803b3f6f288 81933901 8803c4bae000
>  8803c4bae5c8 8803b3f6f2b0 811c6af5 8803c4bae000
>  8285d7f6 0509 8803b3f6f2f0 811c6ce5
>  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 
> Signed-off-by: Mauro Carvalho Chehab 

Acked-by: Hans Verkuil 

Regards,

Hans

> ---
>  drivers/media/media-device.c | 39 +--
>  drivers/media/media-entity.c | 16 
>  include/media/media-device.h |  6 +-
>  3 files changed, 22 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
> index 6e43c95629ea..898a3cf814ba 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_d

[PATCH 1/2] [media] media-device: get rid of the spinlock

2016-04-06 Thread Mauro Carvalho Chehab
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
  8803b3f6f288 81933901 8803c4bae000
 8803c4bae5c8 8803b3f6f2b0 811c6af5 8803c4bae000
 8285d7f6 0509 8803b3f6f2f0 811c6ce5
 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 
Signed-off-by: Mauro Carvalho Chehab 
---
 drivers/media/media-device.c | 39 +--
 drivers/media/media-entity.c | 16 
 include/media/media-device.h |  6 +-
 3 files changed, 22 insertions(+), 39 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6e43c95629ea..898a3cf814ba 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,