proc: stop using BKL
[safe/jmp/linux-2.6] / mm / nommu.c
index 5d8ae08..7695dc8 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/mount.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
+#include "internal.h"
+
 void *high_memory;
 struct page *mem_map;
 unsigned long max_mapnr;
 unsigned long num_physpages;
 unsigned long askedalloc, realalloc;
-atomic_t vm_committed_space = ATOMIC_INIT(0);
+atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0);
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
 int sysctl_overcommit_ratio = 50; /* default is 50% */
 int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
@@ -105,32 +107,39 @@ unsigned int kobjsize(const void *objp)
 {
        struct page *page;
 
-       if (!objp || !((page = virt_to_page(objp))))
+       /*
+        * If the object we have should not have ksize performed on it,
+        * return size of 0
+        */
+       if (!objp || !virt_addr_valid(objp))
                return 0;
 
+       page = virt_to_head_page(objp);
+
+       /*
+        * If the allocator sets PageSlab, we know the pointer came from
+        * kmalloc().
+        */
        if (PageSlab(page))
                return ksize(objp);
 
-       BUG_ON(page->index < 0);
-       BUG_ON(page->index >= MAX_ORDER);
-
-       return (PAGE_SIZE << page->index);
+       /*
+        * The ksize() function is only guaranteed to work for pointers
+        * returned by kmalloc(). So handle arbitrary pointers here.
+        */
+       return PAGE_SIZE << compound_order(page);
 }
 
-/*
- * get a list of pages in an address range belonging to the specified process
- * and indicate the VMA that covers each page
- * - this is potentially dodgy as we may end incrementing the page count of a
- *   slab page or a secondary page from a compound page
- * - don't permit access to VMAs that don't support it, such as I/O mappings
- */
-int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-       unsigned long start, int len, int write, int force,
-       struct page **pages, struct vm_area_struct **vmas)
+int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+                    unsigned long start, int len, int flags,
+               struct page **pages, struct vm_area_struct **vmas)
 {
        struct vm_area_struct *vma;
        unsigned long vm_flags;
        int i;
+       int write = !!(flags & GUP_FLAGS_WRITE);
+       int force = !!(flags & GUP_FLAGS_FORCE);
+       int ignore = !!(flags & GUP_FLAGS_IGNORE_VMA_PERMISSIONS);
 
        /* calculate required read or write permissions.
         * - if 'force' is set, we only require the "MAY" flags.
@@ -145,7 +154,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 
                /* protect what we can, including chardevs */
                if (vma->vm_flags & (VM_IO | VM_PFNMAP) ||
-                   !(vm_flags & vma->vm_flags))
+                   (!ignore && !(vm_flags & vma->vm_flags)))
                        goto finish_or_fault;
 
                if (pages) {
@@ -163,6 +172,30 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 finish_or_fault:
        return i ? : -EFAULT;
 }
+
+
+/*
+ * get a list of pages in an address range belonging to the specified process
+ * and indicate the VMA that covers each page
+ * - this is potentially dodgy as we may end incrementing the page count of a
+ *   slab page or a secondary page from a compound page
+ * - don't permit access to VMAs that don't support it, such as I/O mappings
+ */
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+       unsigned long start, int len, int write, int force,
+       struct page **pages, struct vm_area_struct **vmas)
+{
+       int flags = 0;
+
+       if (write)
+               flags |= GUP_FLAGS_WRITE;
+       if (force)
+               flags |= GUP_FLAGS_FORCE;
+
+       return __get_user_pages(tsk, mm,
+                               start, len, flags,
+                               pages, vmas);
+}
 EXPORT_SYMBOL(get_user_pages);
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -255,6 +288,27 @@ void *vmalloc_node(unsigned long size, int node)
 }
 EXPORT_SYMBOL(vmalloc_node);
 
+#ifndef PAGE_KERNEL_EXEC
+# define PAGE_KERNEL_EXEC PAGE_KERNEL
+#endif
+
+/**
+ *     vmalloc_exec  -  allocate virtually contiguous, executable memory
+ *     @size:          allocation size
+ *
+ *     Kernel-internal function to allocate enough pages to cover @size
+ *     the page level allocator and map them into contiguous and
+ *     executable kernel virtual space.
+ *
+ *     For tight control over page level allocator and protection flags
+ *     use __vmalloc() instead.
+ */
+
+void *vmalloc_exec(unsigned long size)
+{
+       return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
+}
+
 /**
  * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  *     @size:          allocation size
@@ -734,7 +788,7 @@ static unsigned long determine_vm_flags(struct file *file,
         * it's being traced - otherwise breakpoints set in it may interfere
         * with another untraced process
         */
-       if ((flags & MAP_PRIVATE) && (current->ptrace & PT_PTRACED))
+       if ((flags & MAP_PRIVATE) && tracehook_expect_breakpoints(current))
                vm_flags &= ~VM_MAYSHARE;
 
        return vm_flags;
@@ -962,8 +1016,13 @@ unsigned long do_mmap_pgoff(struct file *file,
 
        INIT_LIST_HEAD(&vma->anon_vma_node);
        atomic_set(&vma->vm_usage, 1);
-       if (file)
+       if (file) {
                get_file(file);
+               if (vm_flags & VM_EXECUTABLE) {
+                       added_exe_file_vma(current->mm);
+                       vma->vm_mm = current->mm;
+               }
+       }
        vma->vm_file    = file;
        vma->vm_flags   = vm_flags;
        vma->vm_start   = addr;
@@ -1018,8 +1077,11 @@ unsigned long do_mmap_pgoff(struct file *file,
        up_write(&nommu_vma_sem);
        kfree(vml);
        if (vma) {
-               if (vma->vm_file)
+               if (vma->vm_file) {
                        fput(vma->vm_file);
+                       if (vma->vm_flags & VM_EXECUTABLE)
+                               removed_exe_file_vma(vma->vm_mm);
+               }
                kfree(vma);
        }
        return ret;
@@ -1049,7 +1111,7 @@ EXPORT_SYMBOL(do_mmap_pgoff);
 /*
  * handle mapping disposal for uClinux
  */
-static void put_vma(struct vm_area_struct *vma)
+static void put_vma(struct mm_struct *mm, struct vm_area_struct *vma)
 {
        if (vma) {
                down_write(&nommu_vma_sem);
@@ -1071,8 +1133,11 @@ static void put_vma(struct vm_area_struct *vma)
                        realalloc -= kobjsize(vma);
                        askedalloc -= sizeof(*vma);
 
-                       if (vma->vm_file)
+                       if (vma->vm_file) {
                                fput(vma->vm_file);
+                               if (vma->vm_flags & VM_EXECUTABLE)
+                                       removed_exe_file_vma(mm);
+                       }
                        kfree(vma);
                }
 
@@ -1109,7 +1174,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
  found:
        vml = *parent;
 
-       put_vma(vml->vma);
+       put_vma(mm, vml->vma);
 
        *parent = vml->next;
        realalloc -= kobjsize(vml);
@@ -1154,7 +1219,7 @@ void exit_mmap(struct mm_struct * mm)
 
                while ((tmp = mm->context.vmlist)) {
                        mm->context.vmlist = tmp->next;
-                       put_vma(tmp->vma);
+                       put_vma(mm, tmp->vma);
 
                        realalloc -= kobjsize(tmp);
                        askedalloc -= sizeof(*tmp);
@@ -1389,13 +1454,14 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
 
        /* Don't let a single process grow too big:
           leave 3% of the size of this process for other processes */
-       allowed -= current->mm->total_vm / 32;
+       if (mm)
+               allowed -= mm->total_vm / 32;
 
        /*
         * cast `allowed' as a signed long because vm_committed_space
         * sometimes has a negative value
         */
-       if (atomic_read(&vm_committed_space) < (long)allowed)
+       if (atomic_long_read(&vm_committed_space) < (long)allowed)
                return 0;
 error:
        vm_unacct_memory(pages);