[media] videobuf_vm_{open,close} race fixes
authorAl Viro <viro@ZenIV.linux.org.uk>
Thu, 9 May 2013 18:03:33 +0000 (15:03 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 21 May 2013 11:56:56 +0000 (08:56 -0300)
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: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/v4l2-core/videobuf-dma-contig.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/media/v4l2-core/videobuf-vmalloc.c

index 67f572c3fba2305c91d6ae3a33ea699b63dd9313..8204c881037255300a4658f1769b6f8f90034d05 100644 (file)
@@ -66,11 +66,14 @@ static void __videobuf_dc_free(struct device *dev,
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        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);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 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",
                map, map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                struct videobuf_dma_contig_memory *mem;
 
                dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -126,8 +128,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               videobuf_queue_unlock(q);
        }
+       videobuf_queue_unlock(q);
 }
 
 static const struct vm_operations_struct videobuf_vm_ops = {
index 828e7c10bd701cc9b598f26721a413de7d378cde..9db674ccdc68c11b2751d290f786a6cf56d6a6d9 100644 (file)
@@ -338,11 +338,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        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,
                map->count, vma->vm_start, vma->vm_end);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 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,
                map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                dprintk(1, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                        if (NULL == q->bufs[i])
                                continue;
@@ -374,9 +376,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                        q->bufs[i]->baddr = 0;
                        q->ops->buf_release(q, q->bufs[i]);
                }
-               videobuf_queue_unlock(q);
                kfree(map);
        }
+       videobuf_queue_unlock(q);
        return;
 }
 
index 2ff7fcc77b1104fe7d1ca1a2a9d5738ede27acb7..1365c651c1777bd5f7973281f26baccdad6c8995 100644 (file)
@@ -54,11 +54,14 @@ MODULE_LICENSE("GPL");
 static void videobuf_vm_open(struct vm_area_struct *vma)
 {
        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,
                map->count, vma->vm_start, vma->vm_end);
 
+       videobuf_queue_lock(q);
        map->count++;
+       videobuf_queue_unlock(q);
 }
 
 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,
                map->count, vma->vm_start, vma->vm_end);
 
-       map->count--;
-       if (0 == map->count) {
+       videobuf_queue_lock(q);
+       if (!--map->count) {
                struct videobuf_vmalloc_memory *mem;
 
                dprintk(1, "munmap %p q=%p\n", map, q);
-               videobuf_queue_lock(q);
 
                /* We need first to cancel streams, before unmapping */
                if (q->streaming)
@@ -114,8 +116,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
 
                kfree(map);
 
-               videobuf_queue_unlock(q);
        }
+       videobuf_queue_unlock(q);
 
        return;
 }