diff options
authorHans Verkuil <hans.verkuil@cisco.com>2012-12-04 15:12:47 +0100
committerHans Verkuil <hans.verkuil@cisco.com>2012-12-04 15:12:47 +0100
commit2a2575be262968c7f43f3cacf3a56539b3da68fb (patch)
parentdf5450d51945b4a1a506200e11267626a6d324e3 (diff)
vb2: force output buffers to fault into memory.userptr
When calling get_user_pages for output buffers, the 'write' argument is set to 0 (since the DMA isn't writing to memory), This can cause unexpected results: If you calloc() buffer memory and do not fill that memory afterwards, then the kernel assigns most of that memory to one single physical 'zero' page. If you queue that buffer to the V4L2 driver, then it will call get_user_pages and store the results. Next you dequeue it, fill the buffer and queue it again. Now the V4L2 core code sees the same userptr and length and expects it to be the same buffer that it got before and it will reuse the results of the previous get_user_pages call. But that still points to zero pages, whereas userspace filled it up and so changed the buffer to use different pages. In other words, the pages the V4L2 core knows about are no longer correct. The solution is to always set 'write' to 1 as this will force the kernel to fault in proper pages. We do this for videobuf2-dma-sg.c and videobuf2-vmalloc.c, but not for videobuf2-dma-contig.c since the userptr there is already supposed to point to contiguous memory and shouldn't use the zero page at all. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
2 files changed, 5 insertions, 2 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 25c3b360e1ad..c29f159fbdd4 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -143,7 +143,8 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
num_pages_from_user = get_user_pages(current, current->mm,
vaddr & PAGE_MASK,
- write,
+ 1, /* always set write to force
+ faulting all pages */
1, /* force */
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index a47fd4f589a1..c8d8519a32c5 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -107,7 +107,9 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
/* current->mm->mmap_sem is taken by videobuf2 core */
n_pages = get_user_pages(current, current->mm,
vaddr & PAGE_MASK, buf->n_pages,
- write, 1, /* force */
+ 1, /* always set write to force
+ faulting all pages */
+ 1, /* force */
buf->pages, NULL);
if (n_pages != buf->n_pages)
goto fail_get_user_pages;

Privacy Policy