mm: mark page accessed before we write_end()
[safe/jmp/linux-2.6] / mm / mmap.c
index eb1270b..34579b2 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/hugetlb.h>
 #include <linux/profile.h>
 #include <linux/module.h>
@@ -27,6 +28,7 @@
 #include <linux/mempolicy.h>
 #include <linux/rmap.h>
 #include <linux/mmu_notifier.h>
+#include <linux/perf_counter.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -84,7 +86,10 @@ EXPORT_SYMBOL(vm_get_page_prot);
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS;  /* heuristic overcommit */
 int sysctl_overcommit_ratio = 50;      /* default is 50% */
 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
-atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0);
+struct percpu_counter vm_committed_as;
+
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
 
 /*
  * Check that a process has enough memory to allocate a new virtual
@@ -178,11 +183,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
        if (mm)
                allowed -= mm->total_vm / 32;
 
-       /*
-        * cast `allowed' as a signed long because vm_committed_space
-        * sometimes has a negative value
-        */
-       if (atomic_long_read(&vm_committed_space) < (long)allowed)
+       if (percpu_counter_read_positive(&vm_committed_as) < allowed)
                return 0;
 error:
        vm_unacct_memory(pages);
@@ -1049,6 +1050,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
        if (error)
                return error;
+       error = ima_file_mmap(file, prot);
+       if (error)
+               return error;
 
        return mmap_region(file, addr, len, flags, vm_flags, pgoff);
 }
@@ -1219,6 +1223,8 @@ munmap_back:
        if (correct_wcount)
                atomic_inc(&inode->i_writecount);
 out:
+       perf_counter_mmap(vma);
+
        mm->total_vm += len >> PAGE_SHIFT;
        vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
        if (vm_flags & VM_LOCKED) {
@@ -1571,7 +1577,7 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
         * Overcommit..  This must be the final test, as it will
         * update security statistics.
         */
-       if (security_vm_enough_memory(grow))
+       if (security_vm_enough_memory_mm(mm, grow))
                return -ENOMEM;
 
        /* Ok, everything looks good - let it rip */
@@ -2084,12 +2090,8 @@ void exit_mmap(struct mm_struct *mm)
        unsigned long end;
 
        /* mm's last user has gone, and its about to be pulled down */
-       arch_exit_mmap(mm);
        mmu_notifier_release(mm);
 
-       if (!mm->mmap)  /* Can happen if dup_mmap() received an OOM */
-               return;
-
        if (mm->locked_vm) {
                vma = mm->mmap;
                while (vma) {
@@ -2098,7 +2100,13 @@ void exit_mmap(struct mm_struct *mm)
                        vma = vma->vm_next;
                }
        }
+
+       arch_exit_mmap(mm);
+
        vma = mm->mmap;
+       if (!vma)       /* Can happen if dup_mmap() received an OOM */
+               return;
+
        lru_add_drain();
        flush_cache_mm(mm);
        tlb = tlb_gather_mmu(mm, 1);
@@ -2303,6 +2311,8 @@ int install_special_mapping(struct mm_struct *mm,
 
        mm->total_vm += len >> PAGE_SHIFT;
 
+       perf_counter_mmap(vma);
+
        return 0;
 }
 
@@ -2475,7 +2485,8 @@ void mm_drop_all_locks(struct mm_struct *mm)
  */
 void __init mmap_init(void)
 {
-       vm_area_cachep = kmem_cache_create("vm_area_struct",
-                       sizeof(struct vm_area_struct), 0,
-                       SLAB_PANIC, NULL);
+       int ret;
+
+       ret = percpu_counter_init(&vm_committed_as, 0);
+       VM_BUG_ON(ret);
 }