]> Pileus Git - ~andy/linux/blobdiff - mm/memory.c
mm/hwpoison: don't set migration type twice to avoid holding heavily contend zone...
[~andy/linux] / mm / memory.c
index b3c6bf9a398e9b13f7c5bb1130a72e67034faf75..2b73dbde2274a535aadf90bb3ca2873347ef66f9 100644 (file)
@@ -372,30 +372,6 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)
 
 #endif /* CONFIG_HAVE_RCU_TABLE_FREE */
 
-/*
- * If a p?d_bad entry is found while walking page tables, report
- * the error, before resetting entry to p?d_none.  Usually (but
- * very seldom) called out from the p?d_none_or_clear_bad macros.
- */
-
-void pgd_clear_bad(pgd_t *pgd)
-{
-       pgd_ERROR(*pgd);
-       pgd_clear(pgd);
-}
-
-void pud_clear_bad(pud_t *pud)
-{
-       pud_ERROR(*pud);
-       pud_clear(pud);
-}
-
-void pmd_clear_bad(pmd_t *pmd)
-{
-       pmd_ERROR(*pmd);
-       pmd_clear(pmd);
-}
-
 /*
  * Note: this doesn't free the actual pages themselves. That
  * has been handled earlier when unmapping all the memory regions.
@@ -1505,7 +1481,8 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
        if (pud_none(*pud))
                goto no_page_table;
        if (pud_huge(*pud) && vma->vm_flags & VM_HUGETLB) {
-               BUG_ON(flags & FOLL_GET);
+               if (flags & FOLL_GET)
+                       goto out;
                page = follow_huge_pud(mm, address, pud, flags & FOLL_WRITE);
                goto out;
        }
@@ -1516,8 +1493,20 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
        if (pmd_none(*pmd))
                goto no_page_table;
        if (pmd_huge(*pmd) && vma->vm_flags & VM_HUGETLB) {
-               BUG_ON(flags & FOLL_GET);
                page = follow_huge_pmd(mm, address, pmd, flags & FOLL_WRITE);
+               if (flags & FOLL_GET) {
+                       /*
+                        * Refcount on tail pages are not well-defined and
+                        * shouldn't be taken. The caller should handle a NULL
+                        * return when trying to follow tail pages.
+                        */
+                       if (PageHead(page))
+                               get_page(page);
+                       else {
+                               page = NULL;
+                               goto out;
+                       }
+               }
                goto out;
        }
        if ((flags & FOLL_NUMA) && pmd_numa(*pmd))