gpu: ion: Fix bug in ion_system_heap map_user
authorRebecca Schultz Zavin <rebecca@android.com>
Fri, 13 Dec 2013 22:24:19 +0000 (14:24 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 14 Dec 2013 16:55:40 +0000 (08:55 -0800)
When the requested mmap length was not an integer number of
chunks or the buffer, or if an offset was provided, a bug
would cause extra or incorrect pages of the buffer to be mapped.

Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
[jstultz: modified patch to apply to staging directory]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/android/ion/ion_system_heap.c

index 02726a9702b153106578802d7c6967276546c134..df084695221b977a94bb6f0110c4b9708aad51db 100644 (file)
@@ -292,18 +292,27 @@ int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
 {
        struct sg_table *table = buffer->priv_virt;
        unsigned long addr = vma->vm_start;
-       unsigned long offset = vma->vm_pgoff;
+       unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
        struct scatterlist *sg;
        int i;
 
        for_each_sg(table->sgl, sg, table->nents, i) {
-               if (offset) {
-                       offset--;
+               struct page *page = sg_page(sg);
+               unsigned long remainder = vma->vm_end - addr;
+               unsigned long len = sg_dma_len(sg);
+
+               if (offset >= sg_dma_len(sg)) {
+                       offset -= sg_dma_len(sg);
                        continue;
+               } else if (offset) {
+                       page += offset / PAGE_SIZE;
+                       len = sg_dma_len(sg) - offset;
+                       offset = 0;
                }
-               remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)),
-                               sg_dma_len(sg), vma->vm_page_prot);
-               addr += sg_dma_len(sg);
+               len = min(len, remainder);
+               remap_pfn_range(vma, addr, page_to_pfn(page), len,
+                               vma->vm_page_prot);
+               addr += len;
                if (addr >= vma->vm_end)
                        return 0;
        }