From: Al Viro Date: Thu, 9 May 2013 18:03:33 +0000 (-0300) Subject: [media] videobuf_vm_{open,close} race fixes X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=a242f426108c284049a69710f871cc9f11b13e61;p=linux-beck.git [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: Al Viro Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 67f572c3fba2..8204c8810372 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -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 = { diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 828e7c10bd70..9db674ccdc68 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -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; } diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c index 2ff7fcc77b11..1365c651c177 100644 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf-vmalloc.c @@ -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; }