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

[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
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -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)
	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)


		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 = {
+6 −4
Original line number Original line Diff line number Diff line
@@ -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)
	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)
			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;
}
}


+6 −4
Original line number Original line Diff line number Diff line
@@ -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)
	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)


		kfree(map);
		kfree(map);


		videobuf_queue_unlock(q);
	}
	}
	videobuf_queue_unlock(q);


	return;
	return;
}
}