Commit a242f426 authored by Al Viro's avatar Al Viro Committed by Mauro Carvalho Chehab

[media] videobuf_vm_{open,close} race fixes

just use videobuf_queue_lock(map->q) to protect map->count; vm_area_operations
->open() and ->close() are called just under vma->vm_mm->mmap_sem, which
doesn't help the drivers at all, since clonal VMAs are normally in different
address spaces...
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0735647c
...@@ -66,11 +66,14 @@ static void __videobuf_dc_free(struct device *dev, ...@@ -66,11 +66,14 @@ static void __videobuf_dc_free(struct device *dev,
static void videobuf_vm_open(struct vm_area_struct *vma) static void videobuf_vm_open(struct vm_area_struct *vma)
{ {
struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
map, map->count, vma->vm_start, vma->vm_end); map, map->count, vma->vm_start, vma->vm_end);
videobuf_queue_lock(q);
map->count++; map->count++;
videobuf_queue_unlock(q);
} }
static void videobuf_vm_close(struct vm_area_struct *vma) static void videobuf_vm_close(struct vm_area_struct *vma)
...@@ -82,12 +85,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -82,12 +85,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
map, map->count, vma->vm_start, vma->vm_end); map, map->count, vma->vm_start, vma->vm_end);
map->count--; videobuf_queue_lock(q);
if (0 == map->count) { if (!--map->count) {
struct videobuf_dma_contig_memory *mem; struct videobuf_dma_contig_memory *mem;
dev_dbg(q->dev, "munmap %p q=%p\n", map, q); dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */ /* We need first to cancel streams, before unmapping */
if (q->streaming) if (q->streaming)
...@@ -126,8 +128,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -126,8 +128,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map); kfree(map);
videobuf_queue_unlock(q);
} }
videobuf_queue_unlock(q);
} }
static const struct vm_operations_struct videobuf_vm_ops = { static const struct vm_operations_struct videobuf_vm_ops = {
......
...@@ -338,11 +338,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free); ...@@ -338,11 +338,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
static void videobuf_vm_open(struct vm_area_struct *vma) static void videobuf_vm_open(struct vm_area_struct *vma)
{ {
struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end); map->count, vma->vm_start, vma->vm_end);
videobuf_queue_lock(q);
map->count++; map->count++;
videobuf_queue_unlock(q);
} }
static void videobuf_vm_close(struct vm_area_struct *vma) static void videobuf_vm_close(struct vm_area_struct *vma)
...@@ -355,10 +358,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -355,10 +358,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end); map->count, vma->vm_start, vma->vm_end);
map->count--;
if (0 == map->count) {
dprintk(1, "munmap %p q=%p\n", map, q);
videobuf_queue_lock(q); videobuf_queue_lock(q);
if (!--map->count) {
dprintk(1, "munmap %p q=%p\n", map, q);
for (i = 0; i < VIDEO_MAX_FRAME; i++) { for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i]) if (NULL == q->bufs[i])
continue; continue;
...@@ -374,9 +376,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -374,9 +376,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->baddr = 0; q->bufs[i]->baddr = 0;
q->ops->buf_release(q, q->bufs[i]); q->ops->buf_release(q, q->bufs[i]);
} }
videobuf_queue_unlock(q);
kfree(map); kfree(map);
} }
videobuf_queue_unlock(q);
return; return;
} }
......
...@@ -54,11 +54,14 @@ MODULE_LICENSE("GPL"); ...@@ -54,11 +54,14 @@ MODULE_LICENSE("GPL");
static void videobuf_vm_open(struct vm_area_struct *vma) static void videobuf_vm_open(struct vm_area_struct *vma)
{ {
struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end); map->count, vma->vm_start, vma->vm_end);
videobuf_queue_lock(q);
map->count++; map->count++;
videobuf_queue_unlock(q);
} }
static void videobuf_vm_close(struct vm_area_struct *vma) static void videobuf_vm_close(struct vm_area_struct *vma)
...@@ -70,12 +73,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -70,12 +73,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end); map->count, vma->vm_start, vma->vm_end);
map->count--; videobuf_queue_lock(q);
if (0 == map->count) { if (!--map->count) {
struct videobuf_vmalloc_memory *mem; struct videobuf_vmalloc_memory *mem;
dprintk(1, "munmap %p q=%p\n", map, q); dprintk(1, "munmap %p q=%p\n", map, q);
videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */ /* We need first to cancel streams, before unmapping */
if (q->streaming) if (q->streaming)
...@@ -114,8 +116,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma) ...@@ -114,8 +116,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map); kfree(map);
videobuf_queue_unlock(q);
} }
videobuf_queue_unlock(q);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment