Merge tag 'perf-urgent-for-mingo-4.14-20170928' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / fs / proc / task_mmu.c
index a290966f91eccf57dd82d22941026490b99e3d7c..5589b4bd4b858fa5369728f0a0a2b90b4a3052ae 100644 (file)
@@ -268,8 +268,7 @@ static int do_maps_open(struct inode *inode, struct file *file,
  * Indicate if the VMA is a stack for the given task; for
  * /proc/PID/maps that is the stack of the main task.
  */
-static int is_stack(struct proc_maps_private *priv,
-                   struct vm_area_struct *vma)
+static int is_stack(struct vm_area_struct *vma)
 {
        /*
         * We make no effort to guess what a given thread considers to be
@@ -302,7 +301,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 {
        struct mm_struct *mm = vma->vm_mm;
        struct file *file = vma->vm_file;
-       struct proc_maps_private *priv = m->private;
        vm_flags_t flags = vma->vm_flags;
        unsigned long ino = 0;
        unsigned long long pgoff = 0;
@@ -350,7 +348,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
                        goto done;
                }
 
-               if (is_stack(priv, vma))
+               if (is_stack(vma))
                        name = "[stack]";
        }
 
@@ -549,6 +547,8 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
                        }
                } else if (is_migration_entry(swpent))
                        page = migration_entry_to_page(swpent);
+               else if (is_device_private_entry(swpent))
+                       page = device_private_entry_to_page(swpent);
        } else if (unlikely(IS_ENABLED(CONFIG_SHMEM) && mss->check_shmem_swap
                                                        && pte_none(*pte))) {
                page = find_get_entry(vma->vm_file->f_mapping,
@@ -608,13 +608,14 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 
        ptl = pmd_trans_huge_lock(pmd, vma);
        if (ptl) {
-               smaps_pmd_entry(pmd, addr, walk);
+               if (pmd_present(*pmd))
+                       smaps_pmd_entry(pmd, addr, walk);
                spin_unlock(ptl);
-               return 0;
+               goto out;
        }
 
        if (pmd_trans_unstable(pmd))
-               return 0;
+               goto out;
        /*
         * The mmap_sem held all the way back in m_start() is what
         * keeps khugepaged out of here and from collapsing things
@@ -624,6 +625,7 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        for (; addr != end; pte++, addr += PAGE_SIZE)
                smaps_pte_entry(pte, addr, walk);
        pte_unmap_unlock(pte - 1, ptl);
+out:
        cond_resched();
        return 0;
 }
@@ -712,6 +714,8 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
 
                if (is_migration_entry(swpent))
                        page = migration_entry_to_page(swpent);
+               else if (is_device_private_entry(swpent))
+                       page = device_private_entry_to_page(swpent);
        }
        if (page) {
                int mapcount = page_mapcount(page);
@@ -977,17 +981,22 @@ static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
 {
        pmd_t pmd = *pmdp;
 
-       /* See comment in change_huge_pmd() */
-       pmdp_invalidate(vma, addr, pmdp);
-       if (pmd_dirty(*pmdp))
-               pmd = pmd_mkdirty(pmd);
-       if (pmd_young(*pmdp))
-               pmd = pmd_mkyoung(pmd);
-
-       pmd = pmd_wrprotect(pmd);
-       pmd = pmd_clear_soft_dirty(pmd);
-
-       set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
+       if (pmd_present(pmd)) {
+               /* See comment in change_huge_pmd() */
+               pmdp_invalidate(vma, addr, pmdp);
+               if (pmd_dirty(*pmdp))
+                       pmd = pmd_mkdirty(pmd);
+               if (pmd_young(*pmdp))
+                       pmd = pmd_mkyoung(pmd);
+
+               pmd = pmd_wrprotect(pmd);
+               pmd = pmd_clear_soft_dirty(pmd);
+
+               set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
+       } else if (is_migration_entry(pmd_to_swp_entry(pmd))) {
+               pmd = pmd_swp_clear_soft_dirty(pmd);
+               set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
+       }
 }
 #else
 static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
@@ -1012,6 +1021,9 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
                        goto out;
                }
 
+               if (!pmd_present(*pmd))
+                       goto out;
+
                page = pmd_page(*pmd);
 
                /* Clear accessed and referenced bits. */
@@ -1254,7 +1266,7 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
                if (pm->show_pfn)
                        frame = pte_pfn(pte);
                flags |= PM_PRESENT;
-               page = vm_normal_page(vma, addr, pte);
+               page = _vm_normal_page(vma, addr, pte, true);
                if (pte_soft_dirty(pte))
                        flags |= PM_SOFT_DIRTY;
        } else if (is_swap_pte(pte)) {
@@ -1267,6 +1279,9 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
                flags |= PM_SWAP;
                if (is_migration_entry(entry))
                        page = migration_entry_to_page(entry);
+
+               if (is_device_private_entry(entry))
+                       page = device_private_entry_to_page(entry);
        }
 
        if (page && !PageAnon(page))
@@ -1293,27 +1308,33 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
        if (ptl) {
                u64 flags = 0, frame = 0;
                pmd_t pmd = *pmdp;
+               struct page *page = NULL;
 
                if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(pmd))
                        flags |= PM_SOFT_DIRTY;
 
-               /*
-                * Currently pmd for thp is always present because thp
-                * can not be swapped-out, migrated, or HWPOISONed
-                * (split in such cases instead.)
-                * This if-check is just to prepare for future implementation.
-                */
                if (pmd_present(pmd)) {
-                       struct page *page = pmd_page(pmd);
-
-                       if (page_mapcount(page) == 1)
-                               flags |= PM_MMAP_EXCLUSIVE;
+                       page = pmd_page(pmd);
 
                        flags |= PM_PRESENT;
                        if (pm->show_pfn)
                                frame = pmd_pfn(pmd) +
                                        ((addr & ~PMD_MASK) >> PAGE_SHIFT);
                }
+#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+               else if (is_swap_pmd(pmd)) {
+                       swp_entry_t entry = pmd_to_swp_entry(pmd);
+
+                       frame = swp_type(entry) |
+                               (swp_offset(entry) << MAX_SWAPFILES_SHIFT);
+                       flags |= PM_SWAP;
+                       VM_BUG_ON(!is_pmd_migration_entry(pmd));
+                       page = migration_entry_to_page(entry);
+               }
+#endif
+
+               if (page && page_mapcount(page) == 1)
+                       flags |= PM_MMAP_EXCLUSIVE;
 
                for (; addr != end; addr += PAGE_SIZE) {
                        pagemap_entry_t pme = make_pme(frame, flags);
@@ -1453,7 +1474,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        pm.show_pfn = file_ns_capable(file, &init_user_ns, CAP_SYS_ADMIN);
 
        pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
-       pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY);
+       pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_KERNEL);
        ret = -ENOMEM;
        if (!pm.buffer)
                goto out_mm;
@@ -1746,7 +1767,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
                seq_file_path(m, file, "\n\t= ");
        } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
                seq_puts(m, " heap");
-       } else if (is_stack(proc_priv, vma)) {
+       } else if (is_stack(vma)) {
                seq_puts(m, " stack");
        }