diff options
| author | Hans Verkuil <hverkuil@xs4all.nl> | 2014-01-03 06:10:49 -0500 |
|---|---|---|
| committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-02-04 03:29:46 -0500 |
| commit | cca36e2eecec2b8fc869a50ffd3bd0adeed92b8b (patch) | |
| tree | 88a5b83d47de51a8af1877241dbc753a5ad665ea | |
| parent | 50c88544d225baadd6de1c4365d4ed16cc942a37 (diff) | |
[media] Revert "[media] videobuf_vm_{open,close} race fixes"
This reverts commit a242f426108c284049a69710f871cc9f11b13e61.
That commit actually caused deadlocks, rather then fixing them.
If ext_lock is set to NULL (otherwise videobuf_queue_lock doesn't do
anything), then you get this deadlock:
The driver's mmap function calls videobuf_mmap_mapper which calls
videobuf_queue_lock on q. videobuf_mmap_mapper calls __videobuf_mmap_mapper,
__videobuf_mmap_mapper calls videobuf_vm_open and videobuf_vm_open
calls videobuf_queue_lock on q (introduced by above patch): deadlocked.
This affects drivers using dma-contig and dma-vmalloc. Only dma-sg is
not affected since it doesn't call videobuf_vm_open from __videobuf_mmap_mapper.
Most drivers these days have a non-NULL ext_lock. Those that still use
NULL there are all fairly obscure drivers, which is why this hasn't been
seen earlier.
Since everything worked perfectly fine for many years I prefer to just
revert this patch rather than trying to fix it. videobuf is quite fragile
and I rather not touch it too much. Work is (slowly) progressing to move
everything over to vb2 or at the very least use non-NULL ext_lock in
videobuf.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: <stable@vger.kernel.org> # for v3.11 and up
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Reported-by: Pete Eberlein <pete@sensoray.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
| -rw-r--r-- | drivers/media/v4l2-core/videobuf-dma-contig.c | 12 | ||||
| -rw-r--r-- | drivers/media/v4l2-core/videobuf-dma-sg.c | 10 | ||||
| -rw-r--r-- | drivers/media/v4l2-core/videobuf-vmalloc.c | 10 |
3 files changed, 13 insertions, 19 deletions
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 65411adcd0ea..7e6b209b7002 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c | |||
| @@ -66,14 +66,11 @@ static void __videobuf_dc_free(struct device *dev, | |||
| 66 | static void videobuf_vm_open(struct vm_area_struct *vma) | 66 | static void videobuf_vm_open(struct vm_area_struct *vma) |
| 67 | { | 67 | { |
| 68 | struct videobuf_mapping *map = vma->vm_private_data; | 68 | struct videobuf_mapping *map = vma->vm_private_data; |
| 69 | struct videobuf_queue *q = map->q; | ||
| 70 | 69 | ||
| 71 | dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", | 70 | dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", |
| 72 | map, map->count, vma->vm_start, vma->vm_end); | 71 | map, map->count, vma->vm_start, vma->vm_end); |
| 73 | 72 | ||
| 74 | videobuf_queue_lock(q); | ||
| 75 | map->count++; | 73 | map->count++; |
| 76 | videobuf_queue_unlock(q); | ||
| 77 | } | 74 | } |
| 78 | 75 | ||
| 79 | static void videobuf_vm_close(struct vm_area_struct *vma) | 76 | static void videobuf_vm_close(struct vm_area_struct *vma) |
| @@ -85,11 +82,12 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 85 | dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", | 82 | dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", |
| 86 | map, map->count, vma->vm_start, vma->vm_end); | 83 | map, map->count, vma->vm_start, vma->vm_end); |
| 87 | 84 | ||
| 88 | videobuf_queue_lock(q); | 85 | map->count--; |
| 89 | if (!--map->count) { | 86 | if (0 == map->count) { |
| 90 | struct videobuf_dma_contig_memory *mem; | 87 | struct videobuf_dma_contig_memory *mem; |
| 91 | 88 | ||
| 92 | dev_dbg(q->dev, "munmap %p q=%p\n", map, q); | 89 | dev_dbg(q->dev, "munmap %p q=%p\n", map, q); |
| 90 | videobuf_queue_lock(q); | ||
| 93 | 91 | ||
| 94 | /* We need first to cancel streams, before unmapping */ | 92 | /* We need first to cancel streams, before unmapping */ |
| 95 | if (q->streaming) | 93 | if (q->streaming) |
| @@ -128,8 +126,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 128 | 126 | ||
| 129 | kfree(map); | 127 | kfree(map); |
| 130 | 128 | ||
| 129 | videobuf_queue_unlock(q); | ||
| 131 | } | 130 | } |
| 132 | videobuf_queue_unlock(q); | ||
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | static const struct vm_operations_struct videobuf_vm_ops = { | 133 | static const struct vm_operations_struct videobuf_vm_ops = { |
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 9db674ccdc68..828e7c10bd70 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c | |||
| @@ -338,14 +338,11 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free); | |||
| 338 | static void videobuf_vm_open(struct vm_area_struct *vma) | 338 | static void videobuf_vm_open(struct vm_area_struct *vma) |
| 339 | { | 339 | { |
| 340 | struct videobuf_mapping *map = vma->vm_private_data; | 340 | struct videobuf_mapping *map = vma->vm_private_data; |
| 341 | struct videobuf_queue *q = map->q; | ||
| 342 | 341 | ||
| 343 | dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, | 342 | dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, |
| 344 | map->count, vma->vm_start, vma->vm_end); | 343 | map->count, vma->vm_start, vma->vm_end); |
| 345 | 344 | ||
| 346 | videobuf_queue_lock(q); | ||
| 347 | map->count++; | 345 | map->count++; |
| 348 | videobuf_queue_unlock(q); | ||
| 349 | } | 346 | } |
| 350 | 347 | ||
| 351 | static void videobuf_vm_close(struct vm_area_struct *vma) | 348 | static void videobuf_vm_close(struct vm_area_struct *vma) |
| @@ -358,9 +355,10 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 358 | dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, | 355 | dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, |
| 359 | map->count, vma->vm_start, vma->vm_end); | 356 | map->count, vma->vm_start, vma->vm_end); |
| 360 | 357 | ||
| 361 | videobuf_queue_lock(q); | 358 | map->count--; |
| 362 | if (!--map->count) { | 359 | if (0 == map->count) { |
| 363 | dprintk(1, "munmap %p q=%p\n", map, q); | 360 | dprintk(1, "munmap %p q=%p\n", map, q); |
| 361 | videobuf_queue_lock(q); | ||
| 364 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 362 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
| 365 | if (NULL == q->bufs[i]) | 363 | if (NULL == q->bufs[i]) |
| 366 | continue; | 364 | continue; |
| @@ -376,9 +374,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 376 | q->bufs[i]->baddr = 0; | 374 | q->bufs[i]->baddr = 0; |
| 377 | q->ops->buf_release(q, q->bufs[i]); | 375 | q->ops->buf_release(q, q->bufs[i]); |
| 378 | } | 376 | } |
| 377 | videobuf_queue_unlock(q); | ||
| 379 | kfree(map); | 378 | kfree(map); |
| 380 | } | 379 | } |
| 381 | videobuf_queue_unlock(q); | ||
| 382 | return; | 380 | return; |
| 383 | } | 381 | } |
| 384 | 382 | ||
diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c index 1365c651c177..2ff7fcc77b11 100644 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf-vmalloc.c | |||
| @@ -54,14 +54,11 @@ MODULE_LICENSE("GPL"); | |||
| 54 | static void videobuf_vm_open(struct vm_area_struct *vma) | 54 | static void videobuf_vm_open(struct vm_area_struct *vma) |
| 55 | { | 55 | { |
| 56 | struct videobuf_mapping *map = vma->vm_private_data; | 56 | struct videobuf_mapping *map = vma->vm_private_data; |
| 57 | struct videobuf_queue *q = map->q; | ||
| 58 | 57 | ||
| 59 | dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, | 58 | dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, |
| 60 | map->count, vma->vm_start, vma->vm_end); | 59 | map->count, vma->vm_start, vma->vm_end); |
| 61 | 60 | ||
| 62 | videobuf_queue_lock(q); | ||
| 63 | map->count++; | 61 | map->count++; |
| 64 | videobuf_queue_unlock(q); | ||
| 65 | } | 62 | } |
| 66 | 63 | ||
| 67 | static void videobuf_vm_close(struct vm_area_struct *vma) | 64 | static void videobuf_vm_close(struct vm_area_struct *vma) |
| @@ -73,11 +70,12 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 73 | dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, | 70 | dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, |
| 74 | map->count, vma->vm_start, vma->vm_end); | 71 | map->count, vma->vm_start, vma->vm_end); |
| 75 | 72 | ||
| 76 | videobuf_queue_lock(q); | 73 | map->count--; |
| 77 | if (!--map->count) { | 74 | if (0 == map->count) { |
| 78 | struct videobuf_vmalloc_memory *mem; | 75 | struct videobuf_vmalloc_memory *mem; |
| 79 | 76 | ||
| 80 | dprintk(1, "munmap %p q=%p\n", map, q); | 77 | dprintk(1, "munmap %p q=%p\n", map, q); |
| 78 | videobuf_queue_lock(q); | ||
| 81 | 79 | ||
| 82 | /* We need first to cancel streams, before unmapping */ | 80 | /* We need first to cancel streams, before unmapping */ |
| 83 | if (q->streaming) | 81 | if (q->streaming) |
| @@ -116,8 +114,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
| 116 | 114 | ||
| 117 | kfree(map); | 115 | kfree(map); |
| 118 | 116 | ||
| 117 | videobuf_queue_unlock(q); | ||
| 119 | } | 118 | } |
| 120 | videobuf_queue_unlock(q); | ||
| 121 | 119 | ||
| 122 | return; | 120 | return; |
| 123 | } | 121 | } |
