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 1ad28323fb9faceabb98cfc9f1b3834b365919bb..cd23c081924deed7774f98407748becf817c21b0 100644 (file)
@@ -47,7 +47,7 @@
  * 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);
@@ -96,10 +96,16 @@ void mem_hotplug_done(void)
        cpus_read_unlock();
 }
 
+u64 max_mem_size = U64_MAX;
+
 /* add this memory to iomem resource */
 static struct resource *register_memory_resource(u64 start, u64 size)
 {
        struct resource *res, *conflict;
+
+       if (start + size > max_mem_size)
+               return ERR_PTR(-E2BIG);
+
        res = kzalloc(sizeof(struct resource), GFP_KERNEL);
        if (!res)
                return ERR_PTR(-ENOMEM);
@@ -656,26 +662,40 @@ void __online_page_free(struct page *page)
 }
 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)
+{
+       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)
 {
-       __online_page_set_limits(page);
-       __online_page_increment_counters(page);
-       __online_page_free(page);
+       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)
 {
-       unsigned long i;
        unsigned long onlined_pages = *(unsigned long *)arg;
-       struct page *page;
 
        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);
 
@@ -689,9 +709,9 @@ static void node_states_check_changes_online(unsigned long nr_pages,
 {
        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;
@@ -1365,12 +1385,12 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_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;
                        }
-                       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))
@@ -1496,9 +1516,9 @@ static void node_states_check_changes_offline(unsigned long nr_pages,
        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.
@@ -1612,7 +1632,6 @@ static int __ref __offline_pages(unsigned long start_pfn,
 
                        cond_resched();
                        lru_add_drain_all();
-                       drain_all_pages(zone);
 
                        pfn = scan_movable_pages(pfn, end_pfn);
                        if (pfn) {