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 /drivers/media | |
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>
Diffstat (limited to 'drivers/media')
-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 | } |