Skip to content

Commit 6093d30

Browse files
Hans Verkuilmchehab
Hans Verkuil
authored andcommitted
media: vb2: keep a reference to the request until dqbuf
When vb2_buffer_done is called the buffer is unbound from the request and put. The media_request_object_put also 'put's the request reference. If the application has already closed the request fd, then that means that the request reference at that point goes to 0 and the whole request is released. This means that the control handler associated with the request is also freed and that causes this kernel oops: [174705.995401] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:908 [174705.995411] in_atomic(): 1, irqs_disabled(): 1, pid: 28071, name: vivid-000-vid-o [174705.995416] 2 locks held by vivid-000-vid-o/28071: [174705.995420] #0: 000000001ea3a232 (&dev->mutex#3){....}, at: vivid_thread_vid_out+0x3f5/0x550 [vivid] [174705.995447] #1: 00000000e30a0d1e (&(&q->done_lock)->rlock){....}, at: vb2_buffer_done+0x92/0x1d0 [videobuf2_common] [174705.995460] Preemption disabled at: [174705.995461] [<0000000000000000>] (null) [174705.995472] CPU: 11 PID: 28071 Comm: vivid-000-vid-o Tainted: G W 4.20.0-rc1-test-no #88 [174705.995476] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/19/2017 [174705.995481] Call Trace: [174705.995500] dump_stack+0x46/0x60 [174705.995512] ___might_sleep.cold.79+0xe1/0xf1 [174705.995523] __mutex_lock+0x50/0x8f0 [174705.995531] ? find_held_lock+0x2d/0x90 [174705.995536] ? find_held_lock+0x2d/0x90 [174705.995542] ? find_held_lock+0x2d/0x90 [174705.995564] ? v4l2_ctrl_handler_free.part.13+0x44/0x1d0 [videodev] [174705.995576] v4l2_ctrl_handler_free.part.13+0x44/0x1d0 [videodev] [174705.995590] v4l2_ctrl_request_release+0x1c/0x30 [videodev] [174705.995600] media_request_clean+0x64/0xe0 [media] [174705.995609] media_request_release+0x19/0x40 [media] [174705.995617] vb2_buffer_done+0xef/0x1d0 [videobuf2_common] [174705.995630] vivid_thread_vid_out+0x2c1/0x550 [vivid] [174705.995645] ? vivid_stop_generating_vid_cap+0x1c0/0x1c0 [vivid] [174705.995653] kthread+0x113/0x130 [174705.995659] ? kthread_park+0x80/0x80 [174705.995667] ret_from_fork+0x35/0x40 The vb2_buffer_done function can be called from interrupt context, so anything that sleeps is not allowed. The solution is to increment the request refcount when the buffer is queued and decrement it when the buffer is dequeued. Releasing the request is fine if that happens from VIDIOC_DQBUF. Signed-off-by: Hans Verkuil <[email protected]> Acked-by: Sakari Ailus <[email protected]> Signed-off-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent b7ff0b0 commit 6093d30

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

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

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,8 +1359,12 @@ static void vb2_req_release(struct media_request_object *obj)
13591359
{
13601360
struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
13611361

1362-
if (vb->state == VB2_BUF_STATE_IN_REQUEST)
1362+
if (vb->state == VB2_BUF_STATE_IN_REQUEST) {
13631363
vb->state = VB2_BUF_STATE_DEQUEUED;
1364+
if (vb->request)
1365+
media_request_put(vb->request);
1366+
vb->request = NULL;
1367+
}
13641368
}
13651369

13661370
static const struct media_request_object_ops vb2_core_req_ops = {
@@ -1528,6 +1532,18 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
15281532
return ret;
15291533

15301534
vb->state = VB2_BUF_STATE_IN_REQUEST;
1535+
1536+
/*
1537+
* Increment the refcount and store the request.
1538+
* The request refcount is decremented again when the
1539+
* buffer is dequeued. This is to prevent vb2_buffer_done()
1540+
* from freeing the request from interrupt context, which can
1541+
* happen if the application closed the request fd after
1542+
* queueing the request.
1543+
*/
1544+
media_request_get(req);
1545+
vb->request = req;
1546+
15311547
/* Fill buffer information for the userspace */
15321548
if (pb) {
15331549
call_void_bufop(q, copy_timestamp, vb, pb);
@@ -1749,10 +1765,6 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
17491765
call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
17501766
vb->planes[i].dbuf_mapped = 0;
17511767
}
1752-
if (vb->req_obj.req) {
1753-
media_request_object_unbind(&vb->req_obj);
1754-
media_request_object_put(&vb->req_obj);
1755-
}
17561768
call_void_bufop(q, init_buffer, vb);
17571769
}
17581770

@@ -1797,6 +1809,14 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
17971809
/* go back to dequeued state */
17981810
__vb2_dqbuf(vb);
17991811

1812+
if (WARN_ON(vb->req_obj.req)) {
1813+
media_request_object_unbind(&vb->req_obj);
1814+
media_request_object_put(&vb->req_obj);
1815+
}
1816+
if (vb->request)
1817+
media_request_put(vb->request);
1818+
vb->request = NULL;
1819+
18001820
dprintk(2, "dqbuf of buffer %d, with state %d\n",
18011821
vb->index, vb->state);
18021822

@@ -1903,6 +1923,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
19031923
vb->prepared = false;
19041924
}
19051925
__vb2_dqbuf(vb);
1926+
1927+
if (vb->req_obj.req) {
1928+
media_request_object_unbind(&vb->req_obj);
1929+
media_request_object_put(&vb->req_obj);
1930+
}
1931+
if (vb->request)
1932+
media_request_put(vb->request);
1933+
vb->request = NULL;
19061934
}
19071935
}
19081936

include/media/videobuf2-core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ struct vb2_queue;
239239
* @num_planes: number of planes in the buffer
240240
* on an internal driver queue.
241241
* @timestamp: frame timestamp in ns.
242+
* @request: the request this buffer is associated with.
242243
* @req_obj: used to bind this buffer to a request. This
243244
* request object has a refcount.
244245
*/
@@ -249,6 +250,7 @@ struct vb2_buffer {
249250
unsigned int memory;
250251
unsigned int num_planes;
251252
u64 timestamp;
253+
struct media_request *request;
252254
struct media_request_object req_obj;
253255

254256
/* private: internal use only

0 commit comments

Comments
 (0)