diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2013-08-09 07:11:25 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-08-22 11:01:00 -0400 |
commit | a517cca6b24fc54ac209e44118ec8962051662e3 (patch) | |
tree | 166ea9f4abb6512fbf4585d0760239a9d666b664 /drivers/media/v4l2-core/videobuf2-core.c | |
parent | 1ac7fdeeb52b05e108713d1ccc63e714c2489717 (diff) |
[media] media: vb2: Fix potential deadlock in vb2_prepare_buffer
Commit b037c0fde22b1d3cd0b3c3717d28e54619fc1592 ("media: vb2: fix
potential deadlock in mmap vs. get_userptr handling") fixes an AB-BA
deadlock related to the mmap_sem and driver locks. The same deadlock can
occur in vb2_prepare_buffer(), fix it the same way.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-core.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 35a5b8ff6a09..fb6802c667d3 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -1248,50 +1248,84 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
1248 | */ | 1248 | */ |
1249 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | 1249 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) |
1250 | { | 1250 | { |
1251 | struct rw_semaphore *mmap_sem = NULL; | ||
1251 | struct vb2_buffer *vb; | 1252 | struct vb2_buffer *vb; |
1252 | int ret; | 1253 | int ret; |
1253 | 1254 | ||
1255 | /* | ||
1256 | * In case of user pointer buffers vb2 allocator needs to get direct | ||
1257 | * access to userspace pages. This requires getting read access on | ||
1258 | * mmap semaphore in the current process structure. The same | ||
1259 | * semaphore is taken before calling mmap operation, while both mmap | ||
1260 | * and prepare_buf are called by the driver or v4l2 core with driver's | ||
1261 | * lock held. To avoid a AB-BA deadlock (mmap_sem then driver's lock in | ||
1262 | * mmap and driver's lock then mmap_sem in prepare_buf) the videobuf2 | ||
1263 | * core release driver's lock, takes mmap_sem and then takes again | ||
1264 | * driver's lock. | ||
1265 | * | ||
1266 | * To avoid race with other vb2 calls, which might be called after | ||
1267 | * releasing driver's lock, this operation is performed at the | ||
1268 | * beggining of prepare_buf processing. This way the queue status is | ||
1269 | * consistent after getting driver's lock back. | ||
1270 | */ | ||
1271 | if (q->memory == V4L2_MEMORY_USERPTR) { | ||
1272 | mmap_sem = ¤t->mm->mmap_sem; | ||
1273 | call_qop(q, wait_prepare, q); | ||
1274 | down_read(mmap_sem); | ||
1275 | call_qop(q, wait_finish, q); | ||
1276 | } | ||
1277 | |||
1254 | if (q->fileio) { | 1278 | if (q->fileio) { |
1255 | dprintk(1, "%s(): file io in progress\n", __func__); | 1279 | dprintk(1, "%s(): file io in progress\n", __func__); |
1256 | return -EBUSY; | 1280 | ret = -EBUSY; |
1281 | goto unlock; | ||
1257 | } | 1282 | } |
1258 | 1283 | ||
1259 | if (b->type != q->type) { | 1284 | if (b->type != q->type) { |
1260 | dprintk(1, "%s(): invalid buffer type\n", __func__); | 1285 | dprintk(1, "%s(): invalid buffer type\n", __func__); |
1261 | return -EINVAL; | 1286 | ret = -EINVAL; |
1287 | goto unlock; | ||
1262 | } | 1288 | } |
1263 | 1289 | ||
1264 | if (b->index >= q->num_buffers) { | 1290 | if (b->index >= q->num_buffers) { |
1265 | dprintk(1, "%s(): buffer index out of range\n", __func__); | 1291 | dprintk(1, "%s(): buffer index out of range\n", __func__); |
1266 | return -EINVAL; | 1292 | ret = -EINVAL; |
1293 | goto unlock; | ||
1267 | } | 1294 | } |
1268 | 1295 | ||
1269 | vb = q->bufs[b->index]; | 1296 | vb = q->bufs[b->index]; |
1270 | if (NULL == vb) { | 1297 | if (NULL == vb) { |
1271 | /* Should never happen */ | 1298 | /* Should never happen */ |
1272 | dprintk(1, "%s(): buffer is NULL\n", __func__); | 1299 | dprintk(1, "%s(): buffer is NULL\n", __func__); |
1273 | return -EINVAL; | 1300 | ret = -EINVAL; |
1301 | goto unlock; | ||
1274 | } | 1302 | } |
1275 | 1303 | ||
1276 | if (b->memory != q->memory) { | 1304 | if (b->memory != q->memory) { |
1277 | dprintk(1, "%s(): invalid memory type\n", __func__); | 1305 | dprintk(1, "%s(): invalid memory type\n", __func__); |
1278 | return -EINVAL; | 1306 | ret = -EINVAL; |
1307 | goto unlock; | ||
1279 | } | 1308 | } |
1280 | 1309 | ||
1281 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | 1310 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { |
1282 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); | 1311 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); |
1283 | return -EINVAL; | 1312 | ret = -EINVAL; |
1313 | goto unlock; | ||
1284 | } | 1314 | } |
1285 | ret = __verify_planes_array(vb, b); | 1315 | ret = __verify_planes_array(vb, b); |
1286 | if (ret < 0) | 1316 | if (ret < 0) |
1287 | return ret; | 1317 | goto unlock; |
1318 | |||
1288 | ret = __buf_prepare(vb, b); | 1319 | ret = __buf_prepare(vb, b); |
1289 | if (ret < 0) | 1320 | if (ret < 0) |
1290 | return ret; | 1321 | goto unlock; |
1291 | 1322 | ||
1292 | __fill_v4l2_buffer(vb, b); | 1323 | __fill_v4l2_buffer(vb, b); |
1293 | 1324 | ||
1294 | return 0; | 1325 | unlock: |
1326 | if (mmap_sem) | ||
1327 | up_read(mmap_sem); | ||
1328 | return ret; | ||
1295 | } | 1329 | } |
1296 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); | 1330 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); |
1297 | 1331 | ||