Merge tag 'for-linus-5.1a-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / mm / memory_hotplug.c
index 519f9db063ff5f875e862a0656041660e3bec412..cd23c081924deed7774f98407748becf817c21b0 100644 (file)
@@ -47,7 +47,7 @@
  * and restore_online_page_callback() for generic callback restore.
  */
 
  * and restore_online_page_callback() for generic callback restore.
  */
 
-static void generic_online_page(struct page *page);
+static void generic_online_page(struct page *page, unsigned int order);
 
 static online_page_callback_t online_page_callback = generic_online_page;
 static DEFINE_MUTEX(online_page_callback_lock);
 
 static online_page_callback_t online_page_callback = generic_online_page;
 static DEFINE_MUTEX(online_page_callback_lock);
@@ -662,26 +662,40 @@ void __online_page_free(struct page *page)
 }
 EXPORT_SYMBOL_GPL(__online_page_free);
 
 }
 EXPORT_SYMBOL_GPL(__online_page_free);
 
-static void generic_online_page(struct page *page)
+static void generic_online_page(struct page *page, unsigned int order)
 {
 {
-       __online_page_set_limits(page);
-       __online_page_increment_counters(page);
-       __online_page_free(page);
+       kernel_map_pages(page, 1 << order, 1);
+       __free_pages_core(page, order);
+       totalram_pages_add(1UL << order);
+#ifdef CONFIG_HIGHMEM
+       if (PageHighMem(page))
+               totalhigh_pages_add(1UL << order);
+#endif
+}
+
+static int online_pages_blocks(unsigned long start, unsigned long nr_pages)
+{
+       unsigned long end = start + nr_pages;
+       int order, onlined_pages = 0;
+
+       while (start < end) {
+               order = min(MAX_ORDER - 1,
+                       get_order(PFN_PHYS(end) - PFN_PHYS(start)));
+               (*online_page_callback)(pfn_to_page(start), order);
+
+               onlined_pages += (1UL << order);
+               start += (1UL << order);
+       }
+       return onlined_pages;
 }
 
 static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
                        void *arg)
 {
 }
 
 static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
                        void *arg)
 {
-       unsigned long i;
        unsigned long onlined_pages = *(unsigned long *)arg;
        unsigned long onlined_pages = *(unsigned long *)arg;
-       struct page *page;
 
        if (PageReserved(pfn_to_page(start_pfn)))
 
        if (PageReserved(pfn_to_page(start_pfn)))
-               for (i = 0; i < nr_pages; i++) {
-                       page = pfn_to_page(start_pfn + i);
-                       (*online_page_callback)(page);
-                       onlined_pages++;
-               }
+               onlined_pages += online_pages_blocks(start_pfn, nr_pages);
 
        online_mem_sections(start_pfn, start_pfn + nr_pages);
 
 
        online_mem_sections(start_pfn, start_pfn + nr_pages);
 
@@ -695,9 +709,9 @@ static void node_states_check_changes_online(unsigned long nr_pages,
 {
        int nid = zone_to_nid(zone);
 
 {
        int nid = zone_to_nid(zone);
 
-       arg->status_change_nid = -1;
-       arg->status_change_nid_normal = -1;
-       arg->status_change_nid_high = -1;
+       arg->status_change_nid = NUMA_NO_NODE;
+       arg->status_change_nid_normal = NUMA_NO_NODE;
+       arg->status_change_nid_high = NUMA_NO_NODE;
 
        if (!node_state(nid, N_MEMORY))
                arg->status_change_nid = nid;
 
        if (!node_state(nid, N_MEMORY))
                arg->status_change_nid = nid;
@@ -1194,11 +1208,13 @@ static inline int pageblock_free(struct page *page)
        return PageBuddy(page) && page_order(page) >= pageblock_order;
 }
 
        return PageBuddy(page) && page_order(page) >= pageblock_order;
 }
 
-/* Return the start of the next active pageblock after a given page */
-static struct page *next_active_pageblock(struct page *page)
+/* Return the pfn of the start of the next active pageblock after a given pfn */
+static unsigned long next_active_pageblock(unsigned long pfn)
 {
 {
+       struct page *page = pfn_to_page(pfn);
+
        /* Ensure the starting page is pageblock-aligned */
        /* Ensure the starting page is pageblock-aligned */
-       BUG_ON(page_to_pfn(page) & (pageblock_nr_pages - 1));
+       BUG_ON(pfn & (pageblock_nr_pages - 1));
 
        /* If the entire pageblock is free, move to the end of free page */
        if (pageblock_free(page)) {
 
        /* If the entire pageblock is free, move to the end of free page */
        if (pageblock_free(page)) {
@@ -1206,16 +1222,16 @@ static struct page *next_active_pageblock(struct page *page)
                /* be careful. we don't have locks, page_order can be changed.*/
                order = page_order(page);
                if ((order < MAX_ORDER) && (order >= pageblock_order))
                /* be careful. we don't have locks, page_order can be changed.*/
                order = page_order(page);
                if ((order < MAX_ORDER) && (order >= pageblock_order))
-                       return page + (1 << order);
+                       return pfn + (1 << order);
        }
 
        }
 
-       return page + pageblock_nr_pages;
+       return pfn + pageblock_nr_pages;
 }
 
 }
 
-static bool is_pageblock_removable_nolock(struct page *page)
+static bool is_pageblock_removable_nolock(unsigned long pfn)
 {
 {
+       struct page *page = pfn_to_page(pfn);
        struct zone *zone;
        struct zone *zone;
-       unsigned long pfn;
 
        /*
         * We have to be careful here because we are iterating over memory
 
        /*
         * We have to be careful here because we are iterating over memory
@@ -1238,13 +1254,14 @@ static bool is_pageblock_removable_nolock(struct page *page)
 /* Checks if this range of memory is likely to be hot-removable. */
 bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
 {
 /* Checks if this range of memory is likely to be hot-removable. */
 bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
 {
-       struct page *page = pfn_to_page(start_pfn);
-       unsigned long end_pfn = min(start_pfn + nr_pages, zone_end_pfn(page_zone(page)));
-       struct page *end_page = pfn_to_page(end_pfn);
+       unsigned long end_pfn, pfn;
+
+       end_pfn = min(start_pfn + nr_pages,
+                       zone_end_pfn(page_zone(pfn_to_page(start_pfn))));
 
        /* Check the starting page of each pageblock within the range */
 
        /* Check the starting page of each pageblock within the range */
-       for (; page < end_page; page = next_active_pageblock(page)) {
-               if (!is_pageblock_removable_nolock(page))
+       for (pfn = start_pfn; pfn < end_pfn; pfn = next_active_pageblock(pfn)) {
+               if (!is_pageblock_removable_nolock(pfn))
                        return false;
                cond_resched();
        }
                        return false;
                cond_resched();
        }
@@ -1368,12 +1385,12 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 
                if (PageHuge(page)) {
                        struct page *head = compound_head(page);
 
                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 (compound_order(head) > PFN_SECTION_SHIFT) {
                                ret = -EBUSY;
                                break;
                        }
-                       isolate_huge_page(page, &source);
+                       pfn = page_to_pfn(head) + (1<<compound_order(head)) - 1;
+                       isolate_huge_page(head, &source);
                        continue;
                } else if (PageTransHuge(page))
                        pfn = page_to_pfn(compound_head(page))
                        continue;
                } else if (PageTransHuge(page))
                        pfn = page_to_pfn(compound_head(page))
@@ -1499,9 +1516,9 @@ static void node_states_check_changes_offline(unsigned long nr_pages,
        unsigned long present_pages = 0;
        enum zone_type zt;
 
        unsigned long present_pages = 0;
        enum zone_type zt;
 
-       arg->status_change_nid = -1;
-       arg->status_change_nid_normal = -1;
-       arg->status_change_nid_high = -1;
+       arg->status_change_nid = NUMA_NO_NODE;
+       arg->status_change_nid_normal = NUMA_NO_NODE;
+       arg->status_change_nid_high = NUMA_NO_NODE;
 
        /*
         * Check whether node_states[N_NORMAL_MEMORY] will be changed.
 
        /*
         * Check whether node_states[N_NORMAL_MEMORY] will be changed.
@@ -1615,7 +1632,6 @@ static int __ref __offline_pages(unsigned long start_pfn,
 
                        cond_resched();
                        lru_add_drain_all();
 
                        cond_resched();
                        lru_add_drain_all();
-                       drain_all_pages(zone);
 
                        pfn = scan_movable_pages(pfn, end_pfn);
                        if (pfn) {
 
                        pfn = scan_movable_pages(pfn, end_pfn);
                        if (pfn) {