]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/mmap.c
ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
[mirror_ubuntu-artful-kernel.git] / mm / mmap.c
index 5a0ba9788cdda01fa759a85e1461f2f2aeeb642f..7fdd59ec8d89530c65b0f243eb3fe87144566f91 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -170,7 +170,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
        if (vma->vm_ops && vma->vm_ops->close)
                vma->vm_ops->close(vma);
        if (vma->vm_file)
-               fput(vma->vm_file);
+               vma_fput(vma);
        mpol_put(vma_policy(vma));
        kmem_cache_free(vm_area_cachep, vma);
        return next;
@@ -895,7 +895,7 @@ again:
        if (remove_next) {
                if (file) {
                        uprobe_munmap(next, next->vm_start, next->vm_end);
-                       fput(file);
+                       vma_fput(vma);
                }
                if (next->anon_vma)
                        anon_vma_merge(vma, next);
@@ -1745,8 +1745,8 @@ out:
        return addr;
 
 unmap_and_free_vma:
+       vma_fput(vma);
        vma->vm_file = NULL;
-       fput(file);
 
        /* Undo any partial mapping done by a device driver. */
        unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
@@ -2177,7 +2177,6 @@ static int acct_stack_growth(struct vm_area_struct *vma,
                             unsigned long size, unsigned long grow)
 {
        struct mm_struct *mm = vma->vm_mm;
-       struct rlimit *rlim = current->signal->rlim;
        unsigned long new_start;
 
        /* address space limit tests */
@@ -2185,7 +2184,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
                return -ENOMEM;
 
        /* Stack limit test */
-       if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur))
+       if (size > rlimit(RLIMIT_STACK))
                return -ENOMEM;
 
        /* mlock limit tests */
@@ -2193,7 +2192,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
                unsigned long locked;
                unsigned long limit;
                locked = mm->locked_vm + grow;
-               limit = READ_ONCE(rlim[RLIMIT_MEMLOCK].rlim_cur);
+               limit = rlimit(RLIMIT_MEMLOCK);
                limit >>= PAGE_SHIFT;
                if (locked > limit && !capable(CAP_IPC_LOCK))
                        return -ENOMEM;
@@ -2232,7 +2231,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 
        /* Guard against exceeding limits of the address space. */
        address &= PAGE_MASK;
-       if (address >= TASK_SIZE)
+       if (address >= (TASK_SIZE & PAGE_MASK))
                return -ENOMEM;
        address += PAGE_SIZE;
 
@@ -2244,7 +2243,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                gap_addr = TASK_SIZE;
 
        next = vma->vm_next;
-       if (next && next->vm_start < gap_addr) {
+       if (next && next->vm_start < gap_addr &&
+                       (next->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
                if (!(next->vm_flags & VM_GROWSUP))
                        return -ENOMEM;
                /* Check that both stack segments have the same anon_vma? */
@@ -2315,7 +2315,6 @@ int expand_downwards(struct vm_area_struct *vma,
 {
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *prev;
-       unsigned long gap_addr;
        int error;
 
        address &= PAGE_MASK;
@@ -2324,14 +2323,12 @@ int expand_downwards(struct vm_area_struct *vma,
                return error;
 
        /* Enforce stack_guard_gap */
-       gap_addr = address - stack_guard_gap;
-       if (gap_addr > address)
-               return -ENOMEM;
        prev = vma->vm_prev;
-       if (prev && prev->vm_end > gap_addr) {
-               if (!(prev->vm_flags & VM_GROWSDOWN))
+       /* Check that both stack segments have the same anon_vma? */
+       if (prev && !(prev->vm_flags & VM_GROWSDOWN) &&
+                       (prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
+               if (address - prev->vm_end < stack_guard_gap)
                        return -ENOMEM;
-               /* Check that both stack segments have the same anon_vma? */
        }
 
        /* We must make sure the anon_vma is allocated. */
@@ -2571,7 +2568,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out_free_mpol;
 
        if (new->vm_file)
-               get_file(new->vm_file);
+               vma_get_file(new);
 
        if (new->vm_ops && new->vm_ops->open)
                new->vm_ops->open(new);
@@ -2590,7 +2587,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        if (new->vm_ops && new->vm_ops->close)
                new->vm_ops->close(new);
        if (new->vm_file)
-               fput(new->vm_file);
+               vma_fput(new);
        unlink_anon_vmas(new);
  out_free_mpol:
        mpol_put(vma_policy(new));
@@ -2744,7 +2741,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        struct vm_area_struct *vma;
        unsigned long populate = 0;
        unsigned long ret = -EINVAL;
-       struct file *file;
+       struct file *file, *prfile;
 
        pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.txt.\n",
                     current->comm, current->pid);
@@ -2819,10 +2816,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
                }
        }
 
-       file = get_file(vma->vm_file);
+       vma_get_file(vma);
+       file = vma->vm_file;
+       prfile = vma->vm_prfile;
        ret = do_mmap_pgoff(vma->vm_file, start, size,
                        prot, flags, pgoff, &populate, NULL);
+       if (!IS_ERR_VALUE(ret) && file && prfile) {
+               struct vm_area_struct *new_vma;
+
+               new_vma = find_vma(mm, ret);
+               if (!new_vma->vm_prfile)
+                       new_vma->vm_prfile = prfile;
+               if (new_vma != vma)
+                       get_file(prfile);
+       }
+       /*
+        * two fput()s instead of vma_fput(vma),
+        * coz vma may not be available anymore.
+        */
        fput(file);
+       if (prfile)
+               fput(prfile);
 out:
        up_write(&mm->mmap_sem);
        if (populate)
@@ -3113,7 +3127,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                if (anon_vma_clone(new_vma, vma))
                        goto out_free_mempol;
                if (new_vma->vm_file)
-                       get_file(new_vma->vm_file);
+                       vma_get_file(new_vma);
                if (new_vma->vm_ops && new_vma->vm_ops->open)
                        new_vma->vm_ops->open(new_vma);
                vma_link(mm, new_vma, prev, rb_link, rb_parent);
@@ -3186,8 +3200,12 @@ static int special_mapping_mremap(struct vm_area_struct *new_vma)
 {
        struct vm_special_mapping *sm = new_vma->vm_private_data;
 
+       if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
+               return -EFAULT;
+
        if (sm->mremap)
                return sm->mremap(sm, new_vma);
+
        return 0;
 }