summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebecca Schultz Zavin <rebecca@android.com>2013-12-13 22:24:19 (GMT)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-14 16:55:40 (GMT)
commitb308a7c5cfef6e0d15b8872982645313f415b229 (patch)
tree58d0d35a428012cc53168f18972615b1dab3da1f
parent8fae831288210dae626e212aaab459154b65ed79 (diff)
downloadlinux-b308a7c5cfef6e0d15b8872982645313f415b229.tar.xz
gpu: ion: Fix bug in ion_system_heap map_user
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>
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 02726a9..df08469 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -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;
}