]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/migrate.c
Merge git://git.kvack.org/~bcrl/aio-next
[karo-tx-linux.git] / mm / migrate.c
index 1da0092561a4c0cb1e955e2191885fe3e703a187..9c8d5f59d30bb87e63c9990c085eb646e69b4ed7 100644 (file)
@@ -100,6 +100,10 @@ void putback_movable_pages(struct list_head *l)
        struct page *page2;
 
        list_for_each_entry_safe(page, page2, l, lru) {
+               if (unlikely(PageHuge(page))) {
+                       putback_active_hugepage(page);
+                       continue;
+               }
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
@@ -945,6 +949,16 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        struct page *new_hpage = get_new_page(hpage, private, &result);
        struct anon_vma *anon_vma = NULL;
 
+       /*
+        * Movability of hugepages depends on architectures and hugepage size.
+        * This check is necessary because some callers of hugepage migration
+        * like soft offline and memory hotremove don't walk through page
+        * tables or check whether the hugepage is pmd-based or not before
+        * kicking migration.
+        */
+       if (!hugepage_migration_support(page_hstate(hpage)))
+               return -ENOSYS;
+
        if (!new_hpage)
                return -ENOMEM;
 
@@ -975,6 +989,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 
        unlock_page(hpage);
 out:
+       if (rc != -EAGAIN)
+               putback_active_hugepage(hpage);
        put_page(new_hpage);
        if (result) {
                if (rc)
@@ -1025,7 +1041,11 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
                list_for_each_entry_safe(page, page2, from, lru) {
                        cond_resched();
 
-                       rc = unmap_and_move(get_new_page, private,
+                       if (PageHuge(page))
+                               rc = unmap_and_move_huge_page(get_new_page,
+                                               private, page, pass > 2, mode);
+                       else
+                               rc = unmap_and_move(get_new_page, private,
                                                page, pass > 2, mode);
 
                        switch(rc) {
@@ -1058,32 +1078,6 @@ out:
        return rc;
 }
 
-int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
-                     unsigned long private, enum migrate_mode mode)
-{
-       int pass, rc;
-
-       for (pass = 0; pass < 10; pass++) {
-               rc = unmap_and_move_huge_page(get_new_page, private,
-                                               hpage, pass > 2, mode);
-               switch (rc) {
-               case -ENOMEM:
-                       goto out;
-               case -EAGAIN:
-                       /* try again */
-                       cond_resched();
-                       break;
-               case MIGRATEPAGE_SUCCESS:
-                       goto out;
-               default:
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-out:
-       return rc;
-}
-
 #ifdef CONFIG_NUMA
 /*
  * Move a list of individual pages
@@ -1108,7 +1102,11 @@ static struct page *new_page_node(struct page *p, unsigned long private,
 
        *result = &pm->status;
 
-       return alloc_pages_exact_node(pm->node,
+       if (PageHuge(p))
+               return alloc_huge_page_node(page_hstate(compound_head(p)),
+                                       pm->node);
+       else
+               return alloc_pages_exact_node(pm->node,
                                GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
 }
 
@@ -1168,6 +1166,11 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                                !migrate_all)
                        goto put_and_set;
 
+               if (PageHuge(page)) {
+                       isolate_huge_page(page, &pagelist);
+                       goto put_and_set;
+               }
+
                err = isolate_lru_page(page);
                if (!err) {
                        list_add_tail(&page->lru, &pagelist);
@@ -1190,7 +1193,7 @@ set_status:
                err = migrate_pages(&pagelist, new_page_node,
                                (unsigned long)pm, MIGRATE_SYNC, MR_SYSCALL);
                if (err)
-                       putback_lru_pages(&pagelist);
+                       putback_movable_pages(&pagelist);
        }
 
        up_read(&mm->mmap_sem);
@@ -1468,7 +1471,7 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
                if (!populated_zone(zone))
                        continue;
 
-               if (zone->all_unreclaimable)
+               if (!zone_reclaimable(zone))
                        continue;
 
                /* Avoid waking kswapd by allocating pages_to_migrate pages. */