mm, memory_hotplug: deobfuscate migration part of offlining
[linux-2.6-block.git] / mm / memory_hotplug.c
index 37923f81bfebb7d6fdef396887478b5594a957a7..b9a667d36c554afc46c2d337a2712e6ca8664fb5 100644 (file)
@@ -1339,18 +1339,16 @@ static struct page *new_node_page(struct page *page, unsigned long private)
        return new_page_nodemask(page, nid, &nmask);
 }
 
-#define NR_OFFLINE_AT_ONCE_PAGES       (256)
 static int
 do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 {
        unsigned long pfn;
        struct page *page;
-       int move_pages = NR_OFFLINE_AT_ONCE_PAGES;
        int not_managed = 0;
        int ret = 0;
        LIST_HEAD(source);
 
-       for (pfn = start_pfn; pfn < end_pfn && move_pages > 0; pfn++) {
+       for (pfn = start_pfn; pfn < end_pfn; pfn++) {
                if (!pfn_valid(pfn))
                        continue;
                page = pfn_to_page(pfn);
@@ -1362,8 +1360,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                                ret = -EBUSY;
                                break;
                        }
-                       if (isolate_huge_page(page, &source))
-                               move_pages -= 1 << compound_order(head);
+                       isolate_huge_page(page, &source);
                        continue;
                } else if (PageTransHuge(page))
                        pfn = page_to_pfn(compound_head(page))
@@ -1397,7 +1394,6 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!ret) { /* Success */
                        put_page(page);
                        list_add_tail(&page->lru, &source);
-                       move_pages--;
                        if (!__PageMovable(page))
                                inc_node_page_state(page, NR_ISOLATED_ANON +
                                                    page_is_file_cache(page));
@@ -1611,38 +1607,42 @@ static int __ref __offline_pages(unsigned long start_pfn,
                goto failed_removal_isolated;
        }
 
-       pfn = start_pfn;
-repeat:
-       /* start memory hot removal */
-       ret = -EINTR;
-       if (signal_pending(current)) {
-               reason = "signal backoff";
-               goto failed_removal_isolated;
-       }
+       do {
+               for (pfn = start_pfn; pfn;) {
+                       if (signal_pending(current)) {
+                               ret = -EINTR;
+                               reason = "signal backoff";
+                               goto failed_removal_isolated;
+                       }
 
-       cond_resched();
-       lru_add_drain_all();
-       drain_all_pages(zone);
+                       cond_resched();
+                       lru_add_drain_all();
+                       drain_all_pages(zone);
+
+                       pfn = scan_movable_pages(pfn, end_pfn);
+                       if (pfn) {
+                               /*
+                                * TODO: fatal migration failures should bail
+                                * out
+                                */
+                               do_migrate_range(pfn, end_pfn);
+                       }
+               }
 
-       pfn = scan_movable_pages(start_pfn, end_pfn);
-       if (pfn) { /* We have movable pages */
-               ret = do_migrate_range(pfn, end_pfn);
-               goto repeat;
-       }
+               /*
+                * Dissolve free hugepages in the memory block before doing
+                * offlining actually in order to make hugetlbfs's object
+                * counting consistent.
+                */
+               ret = dissolve_free_huge_pages(start_pfn, end_pfn);
+               if (ret) {
+                       reason = "failure to dissolve huge pages";
+                       goto failed_removal_isolated;
+               }
+               /* check again */
+               offlined_pages = check_pages_isolated(start_pfn, end_pfn);
+       } while (offlined_pages < 0);
 
-       /*
-        * dissolve free hugepages in the memory block before doing offlining
-        * actually in order to make hugetlbfs's object counting consistent.
-        */
-       ret = dissolve_free_huge_pages(start_pfn, end_pfn);
-       if (ret) {
-               reason = "failure to dissolve huge pages";
-               goto failed_removal_isolated;
-       }
-       /* check again */
-       offlined_pages = check_pages_isolated(start_pfn, end_pfn);
-       if (offlined_pages < 0)
-               goto repeat;
        pr_info("Offlined Pages %ld\n", offlined_pages);
        /* Ok, all of our target is isolated.
           We cannot do rollback at this point. */