mm, hugetlb: fix racy resv_huge_pages underflow on UFFDIO_COPY
[linux-block.git] / mm / migrate.c
index 41ff2c9896c4f99e5da575ca83d1952ba155a293..8fc766e52e527e127d17f0e1c1d6a8f54d0b15ee 100644 (file)
@@ -226,8 +226,10 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma,
 
 #ifdef CONFIG_HUGETLB_PAGE
                if (PageHuge(new)) {
+                       unsigned int shift = huge_page_shift(hstate_vma(vma));
+
                        pte = pte_mkhuge(pte);
-                       pte = arch_make_huge_pte(pte, vma, new, 0);
+                       pte = arch_make_huge_pte(pte, shift, vma->vm_flags);
                        set_huge_pte_at(vma->vm_mm, pvmw.address, pvmw.pte, pte);
                        if (PageAnon(new))
                                hugepage_add_anon_rmap(new, vma, pvmw.address);
@@ -551,7 +553,7 @@ static void __copy_gigantic_page(struct page *dst, struct page *src,
        }
 }
 
-static void copy_huge_page(struct page *dst, struct page *src)
+void copy_huge_page(struct page *dst, struct page *src)
 {
        int i;
        int nr_pages;
@@ -626,7 +628,10 @@ void migrate_page_states(struct page *newpage, struct page *page)
        if (PageSwapCache(page))
                ClearPageSwapCache(page);
        ClearPagePrivate(page);
-       set_page_private(page, 0);
+
+       /* page->private contains hugetlb specific flags */
+       if (!PageHuge(page))
+               set_page_private(page, 0);
 
        /*
         * If any waiters have accumulated on the new page then
@@ -1834,8 +1839,8 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
                struct page *page;
                int err = -EFAULT;
 
-               vma = find_vma(mm, addr);
-               if (!vma || addr < vma->vm_start)
+               vma = vma_lookup(mm, addr);
+               if (!vma)
                        goto set_status;
 
                /* FOLL_DUMP to ignore special (like zero) pages */