Skip to content

Commit f035eb4

Browse files
hverkuilmchehab
authored andcommitted
[media] videobuf2: fix lockdep warning
The following lockdep warning has been there ever since commit a517cca one year ago: [ 403.117947] ====================================================== [ 403.117949] [ INFO: possible circular locking dependency detected ] [ 403.117953] 3.16.0-rc6-test-media #961 Not tainted [ 403.117954] ------------------------------------------------------- [ 403.117956] v4l2-ctl/15377 is trying to acquire lock: [ 403.117959] (&dev->mutex#3){+.+.+.}, at: [<ffffffffa005a6c3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.117974] [ 403.117974] but task is already holding lock: [ 403.117976] (&mm->mmap_sem){++++++}, at: [<ffffffff8118291f>] vm_mmap_pgoff+0x6f/0xc0 [ 403.117987] [ 403.117987] which lock already depends on the new lock. [ 403.117987] [ 403.117990] [ 403.117990] the existing dependency chain (in reverse order) is: [ 403.117992] [ 403.117992] -> #1 (&mm->mmap_sem){++++++}: [ 403.117997] [<ffffffff810d733c>] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118006] [<ffffffff810d8bc3>] __lock_acquire+0x4d3/0xd30 [ 403.118010] [<ffffffff810d9da7>] lock_acquire+0xa7/0x160 [ 403.118014] [<ffffffff8118c9ec>] might_fault+0x7c/0xb0 [ 403.118018] [<ffffffffa0028a25>] video_usercopy+0x425/0x610 [videodev] [ 403.118028] [<ffffffffa0028c25>] video_ioctl2+0x15/0x20 [videodev] [ 403.118034] [<ffffffffa0022764>] v4l2_ioctl+0x184/0x1a0 [videodev] [ 403.118040] [<ffffffff811d77d0>] do_vfs_ioctl+0x2f0/0x4f0 [ 403.118307] [<ffffffff811d7a51>] SyS_ioctl+0x81/0xa0 [ 403.118311] [<ffffffff8199dc69>] system_call_fastpath+0x16/0x1b [ 403.118319] [ 403.118319] -> #0 (&dev->mutex#3){+.+.+.}: [ 403.118324] [<ffffffff810d6a96>] check_prevs_add+0x746/0x9f0 [ 403.118329] [<ffffffff810d733c>] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118333] [<ffffffff810d8bc3>] __lock_acquire+0x4d3/0xd30 [ 403.118336] [<ffffffff810d9da7>] lock_acquire+0xa7/0x160 [ 403.118340] [<ffffffff81999664>] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118344] [<ffffffffa005a6c3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118349] [<ffffffffa0022122>] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118354] [<ffffffff81197270>] mmap_region+0x3d0/0x5d0 [ 403.118359] [<ffffffff8119778d>] do_mmap_pgoff+0x31d/0x400 [ 403.118363] [<ffffffff81182940>] vm_mmap_pgoff+0x90/0xc0 [ 403.118366] [<ffffffff81195cef>] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118369] [<ffffffff810085c2>] SyS_mmap+0x22/0x30 [ 403.118376] [<ffffffff8199dc69>] system_call_fastpath+0x16/0x1b [ 403.118381] [ 403.118381] other info that might help us debug this: [ 403.118381] [ 403.118383] Possible unsafe locking scenario: [ 403.118383] [ 403.118385] CPU0 CPU1 [ 403.118387] ---- ---- [ 403.118388] lock(&mm->mmap_sem); [ 403.118391] lock(&dev->mutex#3); [ 403.118394] lock(&mm->mmap_sem); [ 403.118397] lock(&dev->mutex#3); [ 403.118400] [ 403.118400] *** DEADLOCK *** [ 403.118400] [ 403.118403] 1 lock held by v4l2-ctl/15377: [ 403.118405] #0: (&mm->mmap_sem){++++++}, at: [<ffffffff8118291f>] vm_mmap_pgoff+0x6f/0xc0 [ 403.118411] [ 403.118411] stack backtrace: [ 403.118415] CPU: 0 PID: 15377 Comm: v4l2-ctl Not tainted 3.16.0-rc6-test-media #961 [ 403.118418] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013 [ 403.118420] ffffffff82a6c9d0 ffff8800af37fb00 ffffffff819916a2 ffffffff82a6c9d0 [ 403.118425] ffff8800af37fb40 ffffffff810d5715 ffff8802308e4200 0000000000000000 [ 403.118429] ffff8802308e4a48 ffff8802308e4a48 ffff8802308e4200 0000000000000001 [ 403.118433] Call Trace: [ 403.118441] [<ffffffff819916a2>] dump_stack+0x4e/0x7a [ 403.118445] [<ffffffff810d5715>] print_circular_bug+0x1d5/0x2a0 [ 403.118449] [<ffffffff810d6a96>] check_prevs_add+0x746/0x9f0 [ 403.118455] [<ffffffff8119c172>] ? find_vmap_area+0x42/0x70 [ 403.118459] [<ffffffff810d733c>] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118463] [<ffffffff810d8bc3>] __lock_acquire+0x4d3/0xd30 [ 403.118468] [<ffffffff810d9da7>] lock_acquire+0xa7/0x160 [ 403.118472] [<ffffffffa005a6c3>] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118476] [<ffffffffa005a6c3>] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118480] [<ffffffff81999664>] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118484] [<ffffffffa005a6c3>] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118488] [<ffffffffa005a6c3>] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118493] [<ffffffff810d8055>] ? mark_held_locks+0x75/0xa0 [ 403.118497] [<ffffffffa005a6c3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118502] [<ffffffffa0022122>] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118506] [<ffffffff81197270>] mmap_region+0x3d0/0x5d0 [ 403.118510] [<ffffffff8119778d>] do_mmap_pgoff+0x31d/0x400 [ 403.118513] [<ffffffff81182940>] vm_mmap_pgoff+0x90/0xc0 [ 403.118517] [<ffffffff81195cef>] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118521] [<ffffffff810085c2>] SyS_mmap+0x22/0x30 [ 403.118525] [<ffffffff8199dc69>] system_call_fastpath+0x16/0x1b The reason is that vb2_fop_mmap and vb2_fop_get_unmapped_area take the core lock while they are called with the mmap_sem semaphore held. But elsewhere in the code the core lock is taken first but calls to copy_to/from_user() can take the mmap_sem semaphore as well, potentially causing a classical A-B/B-A deadlock. However, the mmap/get_unmapped_area calls really shouldn't take the core lock at all. So what would happen if they don't take the core lock anymore? There are two situations that need to be taken into account: calling mmap while new buffers are being added and calling mmap while buffers are being deleted. The first case works almost fine without a lock: in all cases mmap relies on correctly filled-in q->num_buffers/q->num_planes values and those are only updated by reqbufs and create_buffers *after* any new buffers have been initialized completely. Except in one case: if an error occurred while allocating the buffers it will increase num_buffers and rely on __vb2_queue_free to decrease it again. So there is a short period where the buffer information may be wrong. The second case definitely does pose a problem: buffers may be in the process of being deleted, without the internal structure being updated. In order to fix this a new mutex is added to vb2_queue that is taken when buffers are allocated or deleted, and in vb2_mmap. That way vb2_mmap won't get stale buffer data. Note that this is a problem only for MEMORY_MMAP, so even though __qbuf_userptr and __qbuf_dmabuf also mess around with buffers (mem_priv in particular), this doesn't clash with vb2_mmap or vb2_get_unmapped_area since those are MMAP specific. As an additional bonus the hack in __buf_prepare, the USERPTR case, can be removed as well since mmap() no longer takes the core lock. All in all a much cleaner solution. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
1 parent 23d3090 commit f035eb4

File tree

2 files changed

+21
-37
lines changed

2 files changed

+21
-37
lines changed

drivers/media/v4l2-core/videobuf2-core.c

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
882882
* We already have buffers allocated, so first check if they
883883
* are not in use and can be freed.
884884
*/
885+
mutex_lock(&q->mmap_lock);
885886
if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
887+
mutex_unlock(&q->mmap_lock);
886888
dprintk(1, "memory in use, cannot free\n");
887889
return -EBUSY;
888890
}
@@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
894896
*/
895897
__vb2_queue_cancel(q);
896898
ret = __vb2_queue_free(q, q->num_buffers);
899+
mutex_unlock(&q->mmap_lock);
897900
if (ret)
898901
return ret;
899902

@@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
955958
*/
956959
}
957960

961+
mutex_lock(&q->mmap_lock);
958962
q->num_buffers = allocated_buffers;
959963

960964
if (ret < 0) {
@@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
963967
* from q->num_buffers.
964968
*/
965969
__vb2_queue_free(q, allocated_buffers);
970+
mutex_unlock(&q->mmap_lock);
966971
return ret;
967972
}
973+
mutex_unlock(&q->mmap_lock);
968974

969975
/*
970976
* Return the number of successfully allocated buffers
@@ -1061,6 +1067,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
10611067
*/
10621068
}
10631069

1070+
mutex_lock(&q->mmap_lock);
10641071
q->num_buffers += allocated_buffers;
10651072

10661073
if (ret < 0) {
@@ -1069,8 +1076,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
10691076
* from q->num_buffers.
10701077
*/
10711078
__vb2_queue_free(q, allocated_buffers);
1079+
mutex_unlock(&q->mmap_lock);
10721080
return -ENOMEM;
10731081
}
1082+
mutex_unlock(&q->mmap_lock);
10741083

10751084
/*
10761085
* Return the number of successfully allocated buffers
@@ -1582,7 +1591,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
15821591
static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
15831592
{
15841593
struct vb2_queue *q = vb->vb2_queue;
1585-
struct rw_semaphore *mmap_sem;
15861594
int ret;
15871595

15881596
ret = __verify_length(vb, b);
@@ -1619,26 +1627,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
16191627
ret = __qbuf_mmap(vb, b);
16201628
break;
16211629
case V4L2_MEMORY_USERPTR:
1622-
/*
1623-
* In case of user pointer buffers vb2 allocators need to get
1624-
* direct access to userspace pages. This requires getting
1625-
* the mmap semaphore for read access in the current process
1626-
* structure. The same semaphore is taken before calling mmap
1627-
* operation, while both qbuf/prepare_buf and mmap are called
1628-
* by the driver or v4l2 core with the driver's lock held.
1629-
* To avoid an AB-BA deadlock (mmap_sem then driver's lock in
1630-
* mmap and driver's lock then mmap_sem in qbuf/prepare_buf),
1631-
* the videobuf2 core releases the driver's lock, takes
1632-
* mmap_sem and then takes the driver's lock again.
1633-
*/
1634-
mmap_sem = &current->mm->mmap_sem;
1635-
call_void_qop(q, wait_prepare, q);
1636-
down_read(mmap_sem);
1637-
call_void_qop(q, wait_finish, q);
1638-
16391630
ret = __qbuf_userptr(vb, b);
1640-
1641-
up_read(mmap_sem);
16421631
break;
16431632
case V4L2_MEMORY_DMABUF:
16441633
ret = __qbuf_dmabuf(vb, b);
@@ -2485,7 +2474,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
24852474
return -EINVAL;
24862475
}
24872476

2477+
mutex_lock(&q->mmap_lock);
24882478
ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
2479+
mutex_unlock(&q->mmap_lock);
24892480
if (ret)
24902481
return ret;
24912482

@@ -2504,6 +2495,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
25042495
unsigned long off = pgoff << PAGE_SHIFT;
25052496
struct vb2_buffer *vb;
25062497
unsigned int buffer, plane;
2498+
void *vaddr;
25072499
int ret;
25082500

25092501
if (q->memory != V4L2_MEMORY_MMAP) {
@@ -2520,7 +2512,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
25202512

25212513
vb = q->bufs[buffer];
25222514

2523-
return (unsigned long)vb2_plane_vaddr(vb, plane);
2515+
vaddr = vb2_plane_vaddr(vb, plane);
2516+
return vaddr ? (unsigned long)vaddr : -EINVAL;
25242517
}
25252518
EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
25262519
#endif
@@ -2660,6 +2653,7 @@ int vb2_queue_init(struct vb2_queue *q)
26602653
INIT_LIST_HEAD(&q->queued_list);
26612654
INIT_LIST_HEAD(&q->done_list);
26622655
spin_lock_init(&q->done_lock);
2656+
mutex_init(&q->mmap_lock);
26632657
init_waitqueue_head(&q->done_wq);
26642658

26652659
if (q->buf_struct_size == 0)
@@ -2681,7 +2675,9 @@ void vb2_queue_release(struct vb2_queue *q)
26812675
{
26822676
__vb2_cleanup_fileio(q);
26832677
__vb2_queue_cancel(q);
2678+
mutex_lock(&q->mmap_lock);
26842679
__vb2_queue_free(q, q->num_buffers);
2680+
mutex_unlock(&q->mmap_lock);
26852681
}
26862682
EXPORT_SYMBOL_GPL(vb2_queue_release);
26872683

@@ -3346,15 +3342,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf);
33463342
int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
33473343
{
33483344
struct video_device *vdev = video_devdata(file);
3349-
struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
3350-
int err;
33513345

3352-
if (lock && mutex_lock_interruptible(lock))
3353-
return -ERESTARTSYS;
3354-
err = vb2_mmap(vdev->queue, vma);
3355-
if (lock)
3356-
mutex_unlock(lock);
3357-
return err;
3346+
return vb2_mmap(vdev->queue, vma);
33583347
}
33593348
EXPORT_SYMBOL_GPL(vb2_fop_mmap);
33603349

@@ -3473,15 +3462,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
34733462
unsigned long len, unsigned long pgoff, unsigned long flags)
34743463
{
34753464
struct video_device *vdev = video_devdata(file);
3476-
struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
3477-
int ret;
34783465

3479-
if (lock && mutex_lock_interruptible(lock))
3480-
return -ERESTARTSYS;
3481-
ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
3482-
if (lock)
3483-
mutex_unlock(lock);
3484-
return ret;
3466+
return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
34853467
}
34863468
EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
34873469
#endif

include/media/videobuf2-core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ struct v4l2_fh;
366366
* cannot be started unless at least this number of buffers
367367
* have been queued into the driver.
368368
*
369+
* @mmap_lock: private mutex used when buffers are allocated/freed/mmapped
369370
* @memory: current memory type used
370371
* @bufs: videobuf buffer structures
371372
* @num_buffers: number of allocated/used buffers
@@ -399,6 +400,7 @@ struct vb2_queue {
399400
u32 min_buffers_needed;
400401

401402
/* private: internal use only */
403+
struct mutex mmap_lock;
402404
enum v4l2_memory memory;
403405
struct vb2_buffer *bufs[VIDEO_MAX_FRAME];
404406
unsigned int num_buffers;

0 commit comments

Comments
 (0)