Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / mm / migrate.c
index be26d5cbe56b34d63f8c8ac8b799782f9ef6424b..cae02711181dd7ad0bde55e9eecfc0dd5bccaa83 100644 (file)
@@ -33,7 +33,9 @@
 #include <linux/memcontrol.h>
 #include <linux/syscalls.h>
 #include <linux/hugetlb.h>
+#include <linux/hugetlb_cgroup.h>
 #include <linux/gfp.h>
+#include <linux/balloon_compaction.h>
 
 #include <asm/tlbflush.h>
 
@@ -78,7 +80,30 @@ void putback_lru_pages(struct list_head *l)
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
-               putback_lru_page(page);
+                       putback_lru_page(page);
+       }
+}
+
+/*
+ * Put previously isolated pages back onto the appropriate lists
+ * from where they were once taken off for compaction/migration.
+ *
+ * This function shall be used instead of putback_lru_pages(),
+ * whenever the isolated pageset has been built by isolate_migratepages_range()
+ */
+void putback_movable_pages(struct list_head *l)
+{
+       struct page *page;
+       struct page *page2;
+
+       list_for_each_entry_safe(page, page2, l, lru) {
+               list_del(&page->lru);
+               dec_zone_page_state(page, NR_ISOLATED_ANON +
+                               page_is_file_cache(page));
+               if (unlikely(balloon_page_movable(page)))
+                       balloon_page_putback(page);
+               else
+                       putback_lru_page(page);
        }
 }
 
@@ -90,8 +115,6 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
 {
        struct mm_struct *mm = vma->vm_mm;
        swp_entry_t entry;
-       pgd_t *pgd;
-       pud_t *pud;
        pmd_t *pmd;
        pte_t *ptep, pte;
        spinlock_t *ptl;
@@ -102,19 +125,11 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
                        goto out;
                ptl = &mm->page_table_lock;
        } else {
-               pgd = pgd_offset(mm, addr);
-               if (!pgd_present(*pgd))
+               pmd = mm_find_pmd(mm, addr);
+               if (!pmd)
                        goto out;
-
-               pud = pud_offset(pgd, addr);
-               if (!pud_present(*pud))
-                       goto out;
-
-               pmd = pmd_offset(pud, addr);
                if (pmd_trans_huge(*pmd))
                        goto out;
-               if (!pmd_present(*pmd))
-                       goto out;
 
                ptep = pte_offset_map(pmd, addr);
 
@@ -285,7 +300,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
                /* Anonymous page without mapping */
                if (page_count(page) != 1)
                        return -EAGAIN;
-               return 0;
+               return MIGRATEPAGE_SUCCESS;
        }
 
        spin_lock_irq(&mapping->tree_lock);
@@ -355,7 +370,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
        }
        spin_unlock_irq(&mapping->tree_lock);
 
-       return 0;
+       return MIGRATEPAGE_SUCCESS;
 }
 
 /*
@@ -371,7 +386,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
        if (!mapping) {
                if (page_count(page) != 1)
                        return -EAGAIN;
-               return 0;
+               return MIGRATEPAGE_SUCCESS;
        }
 
        spin_lock_irq(&mapping->tree_lock);
@@ -398,7 +413,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
        page_unfreeze_refs(page, expected_count - 1);
 
        spin_unlock_irq(&mapping->tree_lock);
-       return 0;
+       return MIGRATEPAGE_SUCCESS;
 }
 
 /*
@@ -485,11 +500,11 @@ int migrate_page(struct address_space *mapping,
 
        rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode);
 
-       if (rc)
+       if (rc != MIGRATEPAGE_SUCCESS)
                return rc;
 
        migrate_page_copy(newpage, page);
-       return 0;
+       return MIGRATEPAGE_SUCCESS;
 }
 EXPORT_SYMBOL(migrate_page);
 
@@ -512,7 +527,7 @@ int buffer_migrate_page(struct address_space *mapping,
 
        rc = migrate_page_move_mapping(mapping, newpage, page, head, mode);
 
-       if (rc)
+       if (rc != MIGRATEPAGE_SUCCESS)
                return rc;
 
        /*
@@ -548,7 +563,7 @@ int buffer_migrate_page(struct address_space *mapping,
 
        } while (bh != head);
 
-       return 0;
+       return MIGRATEPAGE_SUCCESS;
 }
 EXPORT_SYMBOL(buffer_migrate_page);
 #endif
@@ -627,7 +642,7 @@ static int fallback_migrate_page(struct address_space *mapping,
  *
  * Return value:
  *   < 0 - error code
- *  == 0 - success
+ *  MIGRATEPAGE_SUCCESS - success
  */
 static int move_to_new_page(struct page *newpage, struct page *page,
                                int remap_swapcache, enum migrate_mode mode)
@@ -664,7 +679,7 @@ static int move_to_new_page(struct page *newpage, struct page *page,
        else
                rc = fallback_migrate_page(mapping, newpage, page, mode);
 
-       if (rc) {
+       if (rc != MIGRATEPAGE_SUCCESS) {
                newpage->mapping = NULL;
        } else {
                if (remap_swapcache)
@@ -682,7 +697,6 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 {
        int rc = -EAGAIN;
        int remap_swapcache = 1;
-       int charge = 0;
        struct mem_cgroup *mem;
        struct anon_vma *anon_vma = NULL;
 
@@ -724,12 +738,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        }
 
        /* charge against new page */
-       charge = mem_cgroup_prepare_migration(page, newpage, &mem, GFP_KERNEL);
-       if (charge == -ENOMEM) {
-               rc = -ENOMEM;
-               goto unlock;
-       }
-       BUG_ON(charge);
+       mem_cgroup_prepare_migration(page, newpage, &mem);
 
        if (PageWriteback(page)) {
                /*
@@ -783,6 +792,18 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
                }
        }
 
+       if (unlikely(balloon_page_movable(page))) {
+               /*
+                * A ballooned page does not need any special attention from
+                * physical to virtual reverse mapping procedures.
+                * Skip any attempt to unmap PTEs or to remap swap cache,
+                * in order to avoid burning cycles at rmap level, and perform
+                * the page migration right away (proteced by page lock).
+                */
+               rc = balloon_page_migrate(newpage, page, mode);
+               goto uncharge;
+       }
+
        /*
         * Corner case handling:
         * 1. When a new swap-cache page is read into, it is added to the LRU
@@ -819,8 +840,9 @@ skip_unmap:
                put_anon_vma(anon_vma);
 
 uncharge:
-       if (!charge)
-               mem_cgroup_end_migration(mem, page, newpage, rc == 0);
+       mem_cgroup_end_migration(mem, page, newpage,
+                                (rc == MIGRATEPAGE_SUCCESS ||
+                                 rc == MIGRATEPAGE_BALLOON_SUCCESS));
 unlock:
        unlock_page(page);
 out:
@@ -852,6 +874,18 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                        goto out;
 
        rc = __unmap_and_move(page, newpage, force, offlining, mode);
+
+       if (unlikely(rc == MIGRATEPAGE_BALLOON_SUCCESS)) {
+               /*
+                * A ballooned page has been migrated already.
+                * Now, it's the time to wrap-up counters,
+                * handle the page back to Buddy and return.
+                */
+               dec_zone_page_state(page, NR_ISOLATED_ANON +
+                                   page_is_file_cache(page));
+               balloon_page_free(page);
+               return MIGRATEPAGE_SUCCESS;
+       }
 out:
        if (rc != -EAGAIN) {
                /*
@@ -931,16 +965,13 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 
        if (anon_vma)
                put_anon_vma(anon_vma);
-       unlock_page(hpage);
 
-out:
-       if (rc != -EAGAIN) {
-               list_del(&hpage->lru);
-               put_page(hpage);
-       }
+       if (!rc)
+               hugetlb_cgroup_migrate(hpage, new_hpage);
 
+       unlock_page(hpage);
+out:
        put_page(new_hpage);
-
        if (result) {
                if (rc)
                        *result = rc;
@@ -996,7 +1027,7 @@ int migrate_pages(struct list_head *from,
                        case -EAGAIN:
                                retry++;
                                break;
-                       case 0:
+                       case MIGRATEPAGE_SUCCESS:
                                break;
                        default:
                                /* Permanent failure */
@@ -1005,59 +1036,40 @@ int migrate_pages(struct list_head *from,
                        }
                }
        }
-       rc = 0;
+       rc = nr_failed + retry;
 out:
        if (!swapwrite)
                current->flags &= ~PF_SWAPWRITE;
 
-       if (rc)
-               return rc;
-
-       return nr_failed + retry;
+       return rc;
 }
 
-int migrate_huge_pages(struct list_head *from,
-               new_page_t get_new_page, unsigned long private, bool offlining,
-               enum migrate_mode mode)
+int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
+                     unsigned long private, bool offlining,
+                     enum migrate_mode mode)
 {
-       int retry = 1;
-       int nr_failed = 0;
-       int pass = 0;
-       struct page *page;
-       struct page *page2;
-       int rc;
-
-       for (pass = 0; pass < 10 && retry; pass++) {
-               retry = 0;
-
-               list_for_each_entry_safe(page, page2, from, lru) {
+       int pass, rc;
+
+       for (pass = 0; pass < 10; pass++) {
+               rc = unmap_and_move_huge_page(get_new_page,
+                                             private, hpage, pass > 2, offlining,
+                                             mode);
+               switch (rc) {
+               case -ENOMEM:
+                       goto out;
+               case -EAGAIN:
+                       /* try again */
                        cond_resched();
-
-                       rc = unmap_and_move_huge_page(get_new_page,
-                                       private, page, pass > 2, offlining,
-                                       mode);
-
-                       switch(rc) {
-                       case -ENOMEM:
-                               goto out;
-                       case -EAGAIN:
-                               retry++;
-                               break;
-                       case 0:
-                               break;
-                       default:
-                               /* Permanent failure */
-                               nr_failed++;
-                               break;
-                       }
+                       break;
+               case MIGRATEPAGE_SUCCESS:
+                       goto out;
+               default:
+                       rc = -EIO;
+                       goto out;
                }
        }
-       rc = 0;
 out:
-       if (rc)
-               return rc;
-
-       return nr_failed + retry;
+       return rc;
 }
 
 #ifdef CONFIG_NUMA
@@ -1226,7 +1238,7 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                        if (node < 0 || node >= MAX_NUMNODES)
                                goto out_pm;
 
-                       if (!node_state(node, N_HIGH_MEMORY))
+                       if (!node_state(node, N_MEMORY))
                                goto out_pm;
 
                        err = -EACCES;