]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/migrate.c
Merge tag 'mmc-v4.3-rc3' of git://git.linaro.org/people/ulf.hansson/mmc
[karo-tx-linux.git] / mm / migrate.c
index eb4267107d1fee9fa2a55e4076c014500e3b1edb..842ecd7aaf7fa6ac1371f6137dc155c91851505c 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/gfp.h>
 #include <linux/balloon_compaction.h>
 #include <linux/mmu_notifier.h>
+#include <linux/page_idle.h>
 
 #include <asm/tlbflush.h>
 
@@ -524,6 +525,11 @@ void migrate_page_copy(struct page *newpage, struct page *page)
                        __set_page_dirty_nobuffers(newpage);
        }
 
+       if (page_is_young(page))
+               set_page_young(newpage);
+       if (page_is_idle(page))
+               set_page_idle(newpage);
+
        /*
         * Copy NUMA information to the new page, to prevent over-eager
         * future migrations of this same page.
@@ -734,6 +740,15 @@ static int move_to_new_page(struct page *newpage, struct page *page,
        if (PageSwapBacked(page))
                SetPageSwapBacked(newpage);
 
+       /*
+        * Indirectly called below, migrate_page_copy() copies PG_dirty and thus
+        * needs newpage's memcg set to transfer memcg dirty page accounting.
+        * So perform memcg migration in two steps:
+        * 1. set newpage->mem_cgroup (here)
+        * 2. clear page->mem_cgroup (below)
+        */
+       set_page_memcg(newpage, page_memcg(page));
+
        mapping = page_mapping(page);
        if (!mapping)
                rc = migrate_page(mapping, newpage, page, mode);
@@ -750,9 +765,10 @@ static int move_to_new_page(struct page *newpage, struct page *page,
                rc = fallback_migrate_page(mapping, newpage, page, mode);
 
        if (rc != MIGRATEPAGE_SUCCESS) {
+               set_page_memcg(newpage, NULL);
                newpage->mapping = NULL;
        } else {
-               mem_cgroup_migrate(page, newpage, false);
+               set_page_memcg(page, NULL);
                if (page_was_mapped)
                        remove_migration_ptes(page, newpage);
                page->mapping = NULL;
@@ -880,8 +896,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        /* Establish migration ptes or remove ptes */
        if (page_mapped(page)) {
                try_to_unmap(page,
-                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
-                       TTU_IGNORE_HWPOISON);
+                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
                page_was_mapped = 1;
        }
 
@@ -952,9 +967,11 @@ out:
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                /* Soft-offlined page shouldn't go through lru cache list */
-               if (reason == MR_MEMORY_FAILURE)
+               if (reason == MR_MEMORY_FAILURE) {
                        put_page(page);
-               else
+                       if (!test_set_page_hwpoison(page))
+                               num_poisoned_pages_inc();
+               } else
                        putback_lru_page(page);
        }
 
@@ -1068,7 +1085,7 @@ out:
        if (rc != MIGRATEPAGE_SUCCESS && put_new_page)
                put_new_page(new_hpage, private);
        else
-               put_page(new_hpage);
+               putback_active_hugepage(new_hpage);
 
        if (result) {
                if (rc)
@@ -1194,7 +1211,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
                return alloc_huge_page_node(page_hstate(compound_head(p)),
                                        pm->node);
        else
-               return alloc_pages_exact_node(pm->node,
+               return __alloc_pages_node(pm->node,
                                GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
 }
 
@@ -1226,7 +1243,9 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma))
                        goto set_status;
 
-               page = follow_page(vma, pp->addr, FOLL_GET|FOLL_SPLIT);
+               /* FOLL_DUMP to ignore special (like zero) pages */
+               page = follow_page(vma, pp->addr,
+                               FOLL_GET | FOLL_SPLIT | FOLL_DUMP);
 
                err = PTR_ERR(page);
                if (IS_ERR(page))
@@ -1236,10 +1255,6 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                if (!page)
                        goto set_status;
 
-               /* Use PageReserved to check for zero page */
-               if (PageReserved(page))
-                       goto put_and_set;
-
                pp->page = page;
                err = page_to_nid(page);
 
@@ -1396,18 +1411,14 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages,
                if (!vma || addr < vma->vm_start)
                        goto set_status;
 
-               page = follow_page(vma, addr, 0);
+               /* FOLL_DUMP to ignore special (like zero) pages */
+               page = follow_page(vma, addr, FOLL_DUMP);
 
                err = PTR_ERR(page);
                if (IS_ERR(page))
                        goto set_status;
 
-               err = -ENOENT;
-               /* Use PageReserved to check for zero page */
-               if (!page || PageReserved(page))
-                       goto set_status;
-
-               err = page_to_nid(page);
+               err = page ? page_to_nid(page) : -ENOENT;
 set_status:
                *status = err;
 
@@ -1560,7 +1571,7 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
        int nid = (int) data;
        struct page *newpage;
 
-       newpage = alloc_pages_exact_node(nid,
+       newpage = __alloc_pages_node(nid,
                                         (GFP_HIGHUSER_MOVABLE |
                                          __GFP_THISNODE | __GFP_NOMEMALLOC |
                                          __GFP_NORETRY | __GFP_NOWARN) &