mm: thp: check pmd migration entry in common path
[sfrench/cifs-2.6.git] / fs / proc / task_mmu.c
index a290966f91eccf57dd82d22941026490b99e3d7c..8eec35af32e49be15fed0b1828d712ced50bfa59 100644 (file)
@@ -608,7 +608,8 @@ 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;
        }
@@ -1012,6 +1013,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. */
@@ -1293,27 +1297,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);