Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02683ffd authored by Andrew G. Harvey's avatar Andrew G. Harvey Committed by Greg Kroah-Hartman
Browse files

UIO: Fix mapping of logical and virtual memory



mmap() doesn't work as expected for UIO_MEM_LOGICAL or UIO_MEM_VIRTUAL
mappings. The offset into the memory needs to be added, otherwise
uio_vma_fault always returns the first page only. Note that for UIO
userspace calls mmap() with offset = N * getpagesize() to access
mapping N. This must be compensated when calculating the offset. A
comment was added to explain this since it is not obvious.

Signed-off-by: default avatarAndrew G. Harvey <agh@cisco.com>
Signed-off-by: default avatarHans J. Koch <hjk@linutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a6030fcc
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -490,15 +490,23 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
	struct uio_device *idev = vma->vm_private_data;
	struct page *page;
	unsigned long offset;

	int mi = uio_find_mem_index(vma);
	if (mi < 0)
		return VM_FAULT_SIGBUS;

	/*
	 * We need to subtract mi because userspace uses offset = N*PAGE_SIZE
	 * to use mem[N].
	 */
	offset = (vmf->pgoff - mi) << PAGE_SHIFT;

	if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
		page = virt_to_page(idev->info->mem[mi].addr);
		page = virt_to_page(idev->info->mem[mi].addr + offset);
	else
		page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
		page = vmalloc_to_page((void *)idev->info->mem[mi].addr
							+ offset);
	get_page(page);
	vmf->page = page;
	return 0;