]> err.no Git - linux-2.6/blobdiff - mm/nommu.c
[NETFILTER]: More __read_mostly annotations
[linux-2.6] / mm / nommu.c
index 829fc904de11052e06d54dcf3a50b9aa7b8ea2c4..8bdde9508f3b80fc8ed5738e3716f6d2d0872c3c 100644 (file)
@@ -221,7 +221,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
  *     Allocate enough pages to cover @size from the page level
  *     allocator and map them into continguos kernel virtual space.
  *
- *     For tight cotrol over page level allocator and protection flags
+ *     For tight control over page level allocator and protection flags
  *     use __vmalloc() instead.
  */
 void *vmalloc(unsigned long size)
@@ -310,6 +310,77 @@ static void show_process_blocks(void)
 }
 #endif /* DEBUG */
 
+/*
+ * add a VMA into a process's mm_struct in the appropriate place in the list
+ * - should be called with mm->mmap_sem held writelocked
+ */
+static void add_vma_to_mm(struct mm_struct *mm, struct vm_list_struct *vml)
+{
+       struct vm_list_struct **ppv;
+
+       for (ppv = &current->mm->context.vmlist; *ppv; ppv = &(*ppv)->next)
+               if ((*ppv)->vma->vm_start > vml->vma->vm_start)
+                       break;
+
+       vml->next = *ppv;
+       *ppv = vml;
+}
+
+/*
+ * look up the first VMA in which addr resides, NULL if none
+ * - should be called with mm->mmap_sem at least held readlocked
+ */
+struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
+{
+       struct vm_list_struct *loop, *vml;
+
+       /* search the vm_start ordered list */
+       vml = NULL;
+       for (loop = mm->context.vmlist; loop; loop = loop->next) {
+               if (loop->vma->vm_start > addr)
+                       break;
+               vml = loop;
+       }
+
+       if (vml && vml->vma->vm_end > addr)
+               return vml->vma;
+
+       return NULL;
+}
+EXPORT_SYMBOL(find_vma);
+
+/*
+ * find a VMA
+ * - we don't extend stack VMAs under NOMMU conditions
+ */
+struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
+{
+       return find_vma(mm, addr);
+}
+
+/*
+ * look up the first VMA exactly that exactly matches addr
+ * - should be called with mm->mmap_sem at least held readlocked
+ */
+static inline struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
+                                                   unsigned long addr)
+{
+       struct vm_list_struct *vml;
+
+       /* search the vm_start ordered list */
+       for (vml = mm->context.vmlist; vml; vml = vml->next) {
+               if (vml->vma->vm_start == addr)
+                       return vml->vma;
+               if (vml->vma->vm_start > addr)
+                       break;
+       }
+
+       return NULL;
+}
+
+/*
+ * find a VMA in the global tree
+ */
 static inline struct vm_area_struct *find_nommu_vma(unsigned long start)
 {
        struct vm_area_struct *vma;
@@ -329,6 +400,9 @@ static inline struct vm_area_struct *find_nommu_vma(unsigned long start)
        return NULL;
 }
 
+/*
+ * add a VMA in the global tree
+ */
 static void add_nommu_vma(struct vm_area_struct *vma)
 {
        struct vm_area_struct *pvma;
@@ -375,6 +449,9 @@ static void add_nommu_vma(struct vm_area_struct *vma)
        rb_insert_color(&vma->vm_rb, &nommu_vma_tree);
 }
 
+/*
+ * delete a VMA from the global list
+ */
 static void delete_nommu_vma(struct vm_area_struct *vma)
 {
        struct address_space *mapping;
@@ -852,8 +929,7 @@ unsigned long do_mmap_pgoff(struct file *file,
        realalloc += kobjsize(vml);
        askedalloc += sizeof(*vml);
 
-       vml->next = current->mm->context.vmlist;
-       current->mm->context.vmlist = vml;
+       add_vma_to_mm(current->mm, vml);
 
        up_write(&nommu_vma_sem);
 
@@ -872,7 +948,8 @@ unsigned long do_mmap_pgoff(struct file *file,
        up_write(&nommu_vma_sem);
        kfree(vml);
        if (vma) {
-               fput(vma->vm_file);
+               if (vma->vm_file)
+                       fput(vma->vm_file);
                kfree(vma);
        }
        return ret;
@@ -932,6 +1009,11 @@ static void put_vma(struct vm_area_struct *vma)
        }
 }
 
+/*
+ * release a mapping
+ * - under NOMMU conditions the parameters must match exactly to the mapping to
+ *   be removed
+ */
 int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
 {
        struct vm_list_struct *vml, **parent;
@@ -941,10 +1023,13 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
        printk("do_munmap:\n");
 #endif
 
-       for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next)
+       for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) {
+               if ((*parent)->vma->vm_start > addr)
+                       break;
                if ((*parent)->vma->vm_start == addr &&
                    ((len == 0) || ((*parent)->vma->vm_end == end)))
                        goto found;
+       }
 
        printk("munmap of non-mmaped memory by process %d (%s): %p\n",
               current->pid, current->comm, (void *) addr);
@@ -970,7 +1055,20 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
        return 0;
 }
 
-/* Release all mmaps. */
+asmlinkage long sys_munmap(unsigned long addr, size_t len)
+{
+       int ret;
+       struct mm_struct *mm = current->mm;
+
+       down_write(&mm->mmap_sem);
+       ret = do_munmap(mm, addr, len);
+       up_write(&mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * Release all mappings
+ */
 void exit_mmap(struct mm_struct * mm)
 {
        struct vm_list_struct *tmp;
@@ -997,37 +1095,26 @@ void exit_mmap(struct mm_struct * mm)
        }
 }
 
-asmlinkage long sys_munmap(unsigned long addr, size_t len)
-{
-       int ret;
-       struct mm_struct *mm = current->mm;
-
-       down_write(&mm->mmap_sem);
-       ret = do_munmap(mm, addr, len);
-       up_write(&mm->mmap_sem);
-       return ret;
-}
-
 unsigned long do_brk(unsigned long addr, unsigned long len)
 {
        return -ENOMEM;
 }
 
 /*
- * Expand (or shrink) an existing mapping, potentially moving it at the
- * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
+ * expand (or shrink) an existing mapping, potentially moving it at the same
+ * time (controlled by the MREMAP_MAYMOVE flag and available VM space)
  *
- * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
- * This option implies MREMAP_MAYMOVE.
+ * under NOMMU conditions, we only permit changing a mapping's size, and only
+ * as long as it stays within the hole allocated by the kmalloc() call in
+ * do_mmap_pgoff() and the block is not shareable
  *
- * on uClinux, we only permit changing a mapping's size, and only as long as it stays within the
- * hole allocated by the kmalloc() call in do_mmap_pgoff() and the block is not shareable
+ * MREMAP_FIXED is not supported under NOMMU conditions
  */
 unsigned long do_mremap(unsigned long addr,
                        unsigned long old_len, unsigned long new_len,
                        unsigned long flags, unsigned long new_addr)
 {
-       struct vm_list_struct *vml = NULL;
+       struct vm_area_struct *vma;
 
        /* insanity checks first */
        if (new_len == 0)
@@ -1036,59 +1123,46 @@ unsigned long do_mremap(unsigned long addr,
        if (flags & MREMAP_FIXED && new_addr != addr)
                return (unsigned long) -EINVAL;
 
-       for (vml = current->mm->context.vmlist; vml; vml = vml->next)
-               if (vml->vma->vm_start == addr)
-                       goto found;
-
-       return (unsigned long) -EINVAL;
+       vma = find_vma_exact(current->mm, addr);
+       if (!vma)
+               return (unsigned long) -EINVAL;
 
- found:
-       if (vml->vma->vm_end != vml->vma->vm_start + old_len)
+       if (vma->vm_end != vma->vm_start + old_len)
                return (unsigned long) -EFAULT;
 
-       if (vml->vma->vm_flags & VM_MAYSHARE)
+       if (vma->vm_flags & VM_MAYSHARE)
                return (unsigned long) -EPERM;
 
        if (new_len > kobjsize((void *) addr))
                return (unsigned long) -ENOMEM;
 
        /* all checks complete - do it */
-       vml->vma->vm_end = vml->vma->vm_start + new_len;
+       vma->vm_end = vma->vm_start + new_len;
 
        askedalloc -= old_len;
        askedalloc += new_len;
 
-       return vml->vma->vm_start;
+       return vma->vm_start;
 }
 
-/*
- * Look up the first VMA which satisfies  addr < vm_end,  NULL if none
- * - should be called with mm->mmap_sem at least readlocked
- */
-struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
+asmlinkage unsigned long sys_mremap(unsigned long addr,
+       unsigned long old_len, unsigned long new_len,
+       unsigned long flags, unsigned long new_addr)
 {
-       struct vm_list_struct *vml;
+       unsigned long ret;
 
-       for (vml = mm->context.vmlist; vml; vml = vml->next)
-               if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end)
-                       return vml->vma;
-
-       return NULL;
+       down_write(&current->mm->mmap_sem);
+       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+       up_write(&current->mm->mmap_sem);
+       return ret;
 }
 
-EXPORT_SYMBOL(find_vma);
-
 struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
                        unsigned int foll_flags)
 {
        return NULL;
 }
 
-struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
-{
-       return NULL;
-}
-
 int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                unsigned long to, unsigned long size, pgprot_t prot)
 {