-
-/**
- * remap_vmalloc_range - map vmalloc pages to userspace
- *
- * @vma: vma to cover (map full range of vma)
- * @addr: vmalloc memory
- * @pgoff: number of pages into addr before first page to map
- * @returns: 0 for success, -Exxx on failure
- *
- * This function checks that addr is a valid vmalloc'ed area, and
- * that it is big enough to cover the vma. Will return failure if
- * that criteria isn't met.
- *
- * Similar to remap_pfn_range (see mm/memory.c)
- */
-int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
- unsigned long pgoff)
-{
- struct vm_struct *area;
- unsigned long uaddr = vma->vm_start;
- unsigned long usize = vma->vm_end - vma->vm_start;
- int ret;
-
- if ((PAGE_SIZE-1) & (unsigned long)addr)
- return -EINVAL;
-
- read_lock(&vmlist_lock);
- area = __find_vm_area(addr);
- if (!area)
- goto out_einval_locked;
-
- if (!(area->flags & VM_USERMAP))
- goto out_einval_locked;
-
- if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE)
- goto out_einval_locked;
- read_unlock(&vmlist_lock);
-
- addr += pgoff << PAGE_SHIFT;
- do {
- struct page *page = vmalloc_to_page(addr);
- ret = vm_insert_page(vma, uaddr, page);
- if (ret)
- return ret;
-
- uaddr += PAGE_SIZE;
- addr += PAGE_SIZE;
- usize -= PAGE_SIZE;
- } while (usize > 0);
-
- /* Prevent "things" like memory migration? VM_flags need a cleanup... */
- vma->vm_flags |= VM_RESERVED;
-
- return ret;
-
-out_einval_locked:
- read_unlock(&vmlist_lock);
- return -EINVAL;
-}
-EXPORT_SYMBOL(remap_vmalloc_range);
-