perf: ftrace: Add set_tracing_options() to set all trace options
[linux-2.6-microblaze.git] / mm / mmap.c
index dcdab26..40248d8 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1030,7 +1030,7 @@ static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1,
  * anon_vmas, nor if same anon_vma is assigned but offsets incompatible.
  *
  * We don't check here for the merged mmap wrapping around the end of pagecache
- * indices (16TB on ia32) because do_mmap_pgoff() does not permit mmap's which
+ * indices (16TB on ia32) because do_mmap() does not permit mmap's which
  * wrap, nor mmaps which cover the final page at index -1UL.
  */
 static int
@@ -1365,11 +1365,11 @@ static inline bool file_mmap_ok(struct file *file, struct inode *inode,
  */
 unsigned long do_mmap(struct file *file, unsigned long addr,
                        unsigned long len, unsigned long prot,
-                       unsigned long flags, vm_flags_t vm_flags,
-                       unsigned long pgoff, unsigned long *populate,
-                       struct list_head *uf)
+                       unsigned long flags, unsigned long pgoff,
+                       unsigned long *populate, struct list_head *uf)
 {
        struct mm_struct *mm = current->mm;
+       vm_flags_t vm_flags;
        int pkey = 0;
 
        *populate = 0;
@@ -1431,7 +1431,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
         * to. we assume access permissions have been handled by the open
         * of the memory object, so we don't do any here.
         */
-       vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
+       vm_flags = calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
                        mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 
        if (flags & MAP_LOCKED)
@@ -1562,11 +1562,12 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
                file = fget(fd);
                if (!file)
                        return -EBADF;
-               if (is_file_hugepages(file))
+               if (is_file_hugepages(file)) {
                        len = ALIGN(len, huge_page_size(hstate_file(file)));
-               retval = -EINVAL;
-               if (unlikely(flags & MAP_HUGETLB && !is_file_hugepages(file)))
+               } else if (unlikely(flags & MAP_HUGETLB)) {
+                       retval = -EINVAL;
                        goto out_fput;
+               }
        } else if (flags & MAP_HUGETLB) {
                struct user_struct *user = NULL;
                struct hstate *hs;
@@ -1689,7 +1690,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                struct list_head *uf)
 {
        struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma, *prev;
+       struct vm_area_struct *vma, *prev, *merge;
        int error;
        struct rb_node **rb_link, *rb_parent;
        unsigned long charged = 0;
@@ -1773,6 +1774,25 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                if (error)
                        goto unmap_and_free_vma;
 
+               /* If vm_flags changed after call_mmap(), we should try merge vma again
+                * as we may succeed this time.
+                */
+               if (unlikely(vm_flags != vma->vm_flags && prev)) {
+                       merge = vma_merge(mm, prev, vma->vm_start, vma->vm_end, vma->vm_flags,
+                               NULL, vma->vm_file, vma->vm_pgoff, NULL, NULL_VM_UFFD_CTX);
+                       if (merge) {
+                               fput(file);
+                               vm_area_free(vma);
+                               vma = merge;
+                               /* Update vm_flags and possible addr to pick up the change. We don't
+                                * warn here if addr changed as the vma is not linked by vma_link().
+                                */
+                               addr = vma->vm_start;
+                               vm_flags = vma->vm_flags;
+                               goto unmap_writable;
+                       }
+               }
+
                /* Can addr have changed??
                 *
                 * Answer: Yes, several device drivers can do it in their
@@ -1795,6 +1815,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
        vma_link(mm, vma, prev, rb_link, rb_parent);
        /* Once vma denies write, undo our temporary denial count */
        if (file) {
+unmap_writable:
                if (vm_flags & VM_SHARED)
                        mapping_unmap_writable(file->f_mapping);
                if (vm_flags & VM_DENYWRITE)
@@ -2209,7 +2230,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
                /*
                 * mmap_region() will call shmem_zero_setup() to create a file,
                 * so use shmem's get_unmapped_area in case it can be huge.
-                * do_mmap_pgoff() will clear pgoff, so match alignment.
+                * do_mmap() will clear pgoff, so match alignment.
                 */
                pgoff = 0;
                get_area = shmem_get_unmapped_area;
@@ -2982,7 +3003,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        }
 
        file = get_file(vma->vm_file);
-       ret = do_mmap_pgoff(vma->vm_file, start, size,
+       ret = do_mmap(vma->vm_file, start, size,
                        prot, flags, pgoff, &populate, NULL);
        fput(file);
 out:
@@ -3202,7 +3223,7 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
         * By setting it to reflect the virtual start address of the
         * vma, merges and splits can happen in a seamless way, just
         * using the existing file pgoff checks and manipulations.
-        * Similarly in do_mmap_pgoff and in do_brk.
+        * Similarly in do_mmap and in do_brk.
         */
        if (vma_is_anonymous(vma)) {
                BUG_ON(vma->anon_vma);