]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/memory_hotplug.c
Merge remote-tracking branch 'sh/sh-latest'
[karo-tx-linux.git] / mm / memory_hotplug.c
index d595606728f9c0d90b9b91e8c49971fbd26c1dc7..ed85fe3870e2c5d0094d47c7aa1086084d98235e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mm_inline.h>
 #include <linux/firmware-map.h>
 #include <linux/stop_machine.h>
+#include <linux/hugetlb.h>
 
 #include <asm/tlbflush.h>
 
@@ -51,14 +52,10 @@ DEFINE_MUTEX(mem_hotplug_mutex);
 void lock_memory_hotplug(void)
 {
        mutex_lock(&mem_hotplug_mutex);
-
-       /* for exclusive hibernation if CONFIG_HIBERNATION=y */
-       lock_system_sleep();
 }
 
 void unlock_memory_hotplug(void)
 {
-       unlock_system_sleep();
        mutex_unlock(&mem_hotplug_mutex);
 }
 
@@ -1230,10 +1227,12 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
 }
 
 /*
- * Scanning pfn is much easier than scanning lru list.
- * Scan pfn from start to end and Find LRU page.
+ * Scan pfn range [start,end) to find movable/migratable pages (LRU pages
+ * and hugepages). We scan pfn because it's much easier than scanning over
+ * linked list. This function returns the pfn of the first found movable
+ * page if it's found, otherwise 0.
  */
-static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
+static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 {
        unsigned long pfn;
        struct page *page;
@@ -1242,6 +1241,13 @@ static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
                        page = pfn_to_page(pfn);
                        if (PageLRU(page))
                                return pfn;
+                       if (PageHuge(page)) {
+                               if (is_hugepage_active(page))
+                                       return pfn;
+                               else
+                                       pfn = round_up(pfn + 1,
+                                               1 << compound_order(page)) - 1;
+                       }
                }
        }
        return 0;
@@ -1262,6 +1268,19 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!pfn_valid(pfn))
                        continue;
                page = pfn_to_page(pfn);
+
+               if (PageHuge(page)) {
+                       struct page *head = compound_head(page);
+                       pfn = page_to_pfn(head) + (1<<compound_order(head)) - 1;
+                       if (compound_order(head) > PFN_SECTION_SHIFT) {
+                               ret = -EBUSY;
+                               break;
+                       }
+                       if (isolate_huge_page(page, &source))
+                               move_pages -= 1 << compound_order(head);
+                       continue;
+               }
+
                if (!get_page_unless_zero(page))
                        continue;
                /*
@@ -1294,7 +1313,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
        }
        if (!list_empty(&source)) {
                if (not_managed) {
-                       putback_lru_pages(&source);
+                       putback_movable_pages(&source);
                        goto out;
                }
 
@@ -1305,7 +1324,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                ret = migrate_pages(&source, alloc_migrate_target, 0,
                                        MIGRATE_SYNC, MR_MEMORY_HOTPLUG);
                if (ret)
-                       putback_lru_pages(&source);
+                       putback_movable_pages(&source);
        }
 out:
        return ret;
@@ -1548,8 +1567,8 @@ repeat:
                drain_all_pages();
        }
 
-       pfn = scan_lru_pages(start_pfn, end_pfn);
-       if (pfn) { /* We have page on LRU */
+       pfn = scan_movable_pages(start_pfn, end_pfn);
+       if (pfn) { /* We have movable pages */
                ret = do_migrate_range(pfn, end_pfn);
                if (!ret) {
                        drain = 1;
@@ -1568,6 +1587,11 @@ repeat:
        yield();
        /* drain pcp pages, this is synchronous. */
        drain_all_pages();
+       /*
+        * dissolve free hugepages in the memory block before doing offlining
+        * actually in order to make hugetlbfs's object counting consistent.
+        */
+       dissolve_free_huge_pages(start_pfn, end_pfn);
        /* check again */
        offlined_pages = check_pages_isolated(start_pfn, end_pfn);
        if (offlined_pages < 0) {