mm: account pmd page tables to the process
[cascardo/linux.git] / mm / mmap.c
index 7f684d5..6a7d36d 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -243,10 +243,7 @@ static void __remove_shared_vm_struct(struct vm_area_struct *vma,
                mapping_unmap_writable(mapping);
 
        flush_dcache_mmap_lock(mapping);
-       if (unlikely(vma->vm_flags & VM_NONLINEAR))
-               list_del_init(&vma->shared.nonlinear);
-       else
-               vma_interval_tree_remove(vma, &mapping->i_mmap);
+       vma_interval_tree_remove(vma, &mapping->i_mmap);
        flush_dcache_mmap_unlock(mapping);
 }
 
@@ -649,10 +646,7 @@ static void __vma_link_file(struct vm_area_struct *vma)
                        atomic_inc(&mapping->i_mmap_writable);
 
                flush_dcache_mmap_lock(mapping);
-               if (unlikely(vma->vm_flags & VM_NONLINEAR))
-                       vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
-               else
-                       vma_interval_tree_insert(vma, &mapping->i_mmap);
+               vma_interval_tree_insert(vma, &mapping->i_mmap);
                flush_dcache_mmap_unlock(mapping);
        }
 }
@@ -789,14 +783,11 @@ again:                    remove_next = 1 + (end > next->vm_end);
 
        if (file) {
                mapping = file->f_mapping;
-               if (!(vma->vm_flags & VM_NONLINEAR)) {
-                       root = &mapping->i_mmap;
-                       uprobe_munmap(vma, vma->vm_start, vma->vm_end);
+               root = &mapping->i_mmap;
+               uprobe_munmap(vma, vma->vm_start, vma->vm_end);
 
-                       if (adjust_next)
-                               uprobe_munmap(next, next->vm_start,
-                                                       next->vm_end);
-               }
+               if (adjust_next)
+                       uprobe_munmap(next, next->vm_start, next->vm_end);
 
                i_mmap_lock_write(mapping);
                if (insert) {
@@ -2634,6 +2625,75 @@ SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len)
        return vm_munmap(addr, len);
 }
 
+
+/*
+ * Emulation of deprecated remap_file_pages() syscall.
+ */
+SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
+               unsigned long, prot, unsigned long, pgoff, unsigned long, flags)
+{
+
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       unsigned long populate = 0;
+       unsigned long ret = -EINVAL;
+       struct file *file;
+
+       pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. "
+                       "See Documentation/vm/remap_file_pages.txt.\n",
+                       current->comm, current->pid);
+
+       if (prot)
+               return ret;
+       start = start & PAGE_MASK;
+       size = size & PAGE_MASK;
+
+       if (start + size <= start)
+               return ret;
+
+       /* Does pgoff wrap? */
+       if (pgoff + (size >> PAGE_SHIFT) < pgoff)
+               return ret;
+
+       down_write(&mm->mmap_sem);
+       vma = find_vma(mm, start);
+
+       if (!vma || !(vma->vm_flags & VM_SHARED))
+               goto out;
+
+       if (start < vma->vm_start || start + size > vma->vm_end)
+               goto out;
+
+       if (pgoff == linear_page_index(vma, start)) {
+               ret = 0;
+               goto out;
+       }
+
+       prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
+       prot |= vma->vm_flags & VM_WRITE ? PROT_WRITE : 0;
+       prot |= vma->vm_flags & VM_EXEC ? PROT_EXEC : 0;
+
+       flags &= MAP_NONBLOCK;
+       flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
+       if (vma->vm_flags & VM_LOCKED) {
+               flags |= MAP_LOCKED;
+               /* drop PG_Mlocked flag for over-mapped range */
+               munlock_vma_pages_range(vma, start, start + size);
+       }
+
+       file = get_file(vma->vm_file);
+       ret = do_mmap_pgoff(vma->vm_file, start, size,
+                       prot, flags, pgoff, &populate);
+       fput(file);
+out:
+       up_write(&mm->mmap_sem);
+       if (populate)
+               mm_populate(ret, populate);
+       if (!IS_ERR_VALUE(ret))
+               ret = 0;
+       return ret;
+}
+
 static inline void verify_mm_writelocked(struct mm_struct *mm)
 {
 #ifdef CONFIG_DEBUG_VM
@@ -2793,7 +2853,9 @@ void exit_mmap(struct mm_struct *mm)
        vm_unacct_memory(nr_accounted);
 
        WARN_ON(atomic_long_read(&mm->nr_ptes) >
-                       (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
+                       round_up(FIRST_USER_ADDRESS, PMD_SIZE) >> PMD_SHIFT);
+       WARN_ON(mm_nr_pmds(mm) >
+                       round_up(FIRST_USER_ADDRESS, PUD_SIZE) >> PUD_SHIFT);
 }
 
 /* Insert vm structure into process list sorted by address
@@ -3108,8 +3170,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
  *
  * mmap_sem in write mode is required in order to block all operations
  * that could modify pagetables and free pages without need of
- * altering the vma layout (for example populate_range() with
- * nonlinear vmas). It's also needed in write mode to avoid new
+ * altering the vma layout. It's also needed in write mode to avoid new
  * anon_vmas to be associated with existing vmas.
  *
  * A single task can't take more than one mm_take_all_locks() in a row