diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-12-13 11:13:40 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-01-07 04:08:47 -0500 |
commit | 63faabfd89f4db9862ae2a663193e511419c67eb (patch) | |
tree | daf06328aa1e9e234cbb481e9a5f5c12a1818ac1 | |
parent | 4138111a27859dcc56a5592c804dd16bb12a23d1 (diff) |
[media] vb2: fix race condition between REQBUFS and QBUF/PREPARE_BUF
When preparing a buffer the queue lock is released for a short while
if the memory mode is USERPTR (see __buf_prepare for the details), which
would allow a race with a REQBUFS which can free the buffers. Removing the
buffers from underneath __buf_prepare is obviously a bad idea, so we
check if any of the buffers is in the state PREPARING, and if so we
just return -EAGAIN.
If this happens, then the application does something really strange. The
REQBUFS call can be retried safely, since this situation is transient.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ca255da65108..a9a9c6a1c158 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -298,10 +298,28 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) | |||
298 | * related information, if no buffers are left return the queue to an | 298 | * related information, if no buffers are left return the queue to an |
299 | * uninitialized state. Might be called even if the queue has already been freed. | 299 | * uninitialized state. Might be called even if the queue has already been freed. |
300 | */ | 300 | */ |
301 | static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | 301 | static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) |
302 | { | 302 | { |
303 | unsigned int buffer; | 303 | unsigned int buffer; |
304 | 304 | ||
305 | /* | ||
306 | * Sanity check: when preparing a buffer the queue lock is released for | ||
307 | * a short while (see __buf_prepare for the details), which would allow | ||
308 | * a race with a reqbufs which can call this function. Removing the | ||
309 | * buffers from underneath __buf_prepare is obviously a bad idea, so we | ||
310 | * check if any of the buffers is in the state PREPARING, and if so we | ||
311 | * just return -EAGAIN. | ||
312 | */ | ||
313 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; | ||
314 | ++buffer) { | ||
315 | if (q->bufs[buffer] == NULL) | ||
316 | continue; | ||
317 | if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { | ||
318 | dprintk(1, "reqbufs: preparing buffers, cannot free\n"); | ||
319 | return -EAGAIN; | ||
320 | } | ||
321 | } | ||
322 | |||
305 | /* Call driver-provided cleanup function for each buffer, if provided */ | 323 | /* Call driver-provided cleanup function for each buffer, if provided */ |
306 | if (q->ops->buf_cleanup) { | 324 | if (q->ops->buf_cleanup) { |
307 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; | 325 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
@@ -326,6 +344,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | |||
326 | if (!q->num_buffers) | 344 | if (!q->num_buffers) |
327 | q->memory = 0; | 345 | q->memory = 0; |
328 | INIT_LIST_HEAD(&q->queued_list); | 346 | INIT_LIST_HEAD(&q->queued_list); |
347 | return 0; | ||
329 | } | 348 | } |
330 | 349 | ||
331 | /** | 350 | /** |
@@ -658,7 +677,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
658 | return -EBUSY; | 677 | return -EBUSY; |
659 | } | 678 | } |
660 | 679 | ||
661 | __vb2_queue_free(q, q->num_buffers); | 680 | ret = __vb2_queue_free(q, q->num_buffers); |
681 | if (ret) | ||
682 | return ret; | ||
662 | 683 | ||
663 | /* | 684 | /* |
664 | * In case of REQBUFS(0) return immediately without calling | 685 | * In case of REQBUFS(0) return immediately without calling |