]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/huge_memory.c
mm: mempolicy: Use _PAGE_NUMA to migrate pages
[mirror_ubuntu-artful-kernel.git] / mm / huge_memory.c
index f5f37630c54da63c867afeca0e159c08f4beb8e3..5723b551c023cdbb5c951d7fe2cc80a39c5888ec 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/freezer.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
+#include <linux/migrate.h>
 #include <asm/tlb.h>
 #include <asm/pgalloc.h>
 #include "internal.h"
@@ -1019,17 +1020,39 @@ out:
 }
 
 /* NUMA hinting page fault entry point for trans huge pmds */
-int do_huge_pmd_numa_page(struct mm_struct *mm, unsigned long addr,
-                               pmd_t pmd, pmd_t *pmdp)
+int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
+                               unsigned long addr, pmd_t pmd, pmd_t *pmdp)
 {
-       struct page *page;
+       struct page *page = NULL;
        unsigned long haddr = addr & HPAGE_PMD_MASK;
+       int target_nid;
 
        spin_lock(&mm->page_table_lock);
        if (unlikely(!pmd_same(pmd, *pmdp)))
                goto out_unlock;
 
        page = pmd_page(pmd);
+       get_page(page);
+       spin_unlock(&mm->page_table_lock);
+
+       target_nid = mpol_misplaced(page, vma, haddr);
+       if (target_nid == -1)
+               goto clear_pmdnuma;
+
+       /*
+        * Due to lacking code to migrate thp pages, we'll split
+        * (which preserves the special PROT_NONE) and re-take the
+        * fault on the normal pages.
+        */
+       split_huge_page(page);
+       put_page(page);
+       return 0;
+
+clear_pmdnuma:
+       spin_lock(&mm->page_table_lock);
+       if (unlikely(!pmd_same(pmd, *pmdp)))
+               goto out_unlock;
+
        pmd = pmd_mknonnuma(pmd);
        set_pmd_at(mm, haddr, pmdp, pmd);
        VM_BUG_ON(pmd_numa(*pmdp));
@@ -1037,6 +1060,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, unsigned long addr,
 
 out_unlock:
        spin_unlock(&mm->page_table_lock);
+       if (page)
+               put_page(page);
        return 0;
 }