summaryrefslogtreecommitdiff
path: root/mm/mmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mmap.c')
-rw-r--r--mm/mmap.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index bab7f48ae2fd..75839312a9be 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -233,14 +233,9 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
/* Obtain the address to map to. we verify (or select) it and ensure
* that it represents a valid section of the address space.
*/
- if (flags & MAP_FIXED) {
- if (addr & ~PAGE_MASK)
- return -EINVAL;
- } else {
- addr = get_unmapped_area(addr, len);
- if (!addr)
- return -ENOMEM;
- }
+ addr = get_unmapped_area(file, addr, len, pgoff, flags);
+ if (addr & ~PAGE_MASK)
+ return addr;
/* Do simple checking here so the lower-level routines won't have
* to. we assume access permissions have been handled by the open
@@ -393,30 +388,51 @@ free_vma:
}
/* Get an address range which is currently unmapped.
- * For mmap() without MAP_FIXED and shmat() with addr=0.
- * Return value 0 means ENOMEM.
+ * For shmat() with addr=0.
+ *
+ * Ugly calling convention alert:
+ * Return value with the low bits set means error value,
+ * ie
+ * if (ret & ~PAGE_MASK)
+ * error = ret;
+ *
+ * This function "knows" that -ENOMEM has the bits set.
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
-unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
+static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
- struct vm_area_struct * vmm;
+ struct vm_area_struct *vma;
if (len > TASK_SIZE)
- return 0;
+ return -ENOMEM;
if (!addr)
addr = TASK_UNMAPPED_BASE;
addr = PAGE_ALIGN(addr);
- for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
- /* At this point: (!vmm || addr < vmm->vm_end). */
+ for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+ /* At this point: (!vma || addr < vma->vm_end). */
if (TASK_SIZE - len < addr)
- return 0;
- if (!vmm || addr + len <= vmm->vm_start)
+ return -ENOMEM;
+ if (!vma || addr + len <= vma->vm_start)
return addr;
- addr = vmm->vm_end;
+ addr = vma->vm_end;
}
}
-#endif
+#endif
+
+unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ if (flags & MAP_FIXED) {
+ if (addr & ~PAGE_MASK)
+ return -EINVAL;
+ return addr;
+ }
+
+ if (file && file->f_op && file->f_op->get_unmapped_area)
+ return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags);
+
+ return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+}
#define vm_avl_empty (struct vm_area_struct *) NULL