Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[cascardo/linux.git] / mm / memory_hotplug.c
index 252e1db..9fab107 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/stop_machine.h>
 #include <linux/hugetlb.h>
 #include <linux/memblock.h>
+#include <linux/bootmem.h>
 
 #include <asm/tlbflush.h>
 
@@ -1066,6 +1067,16 @@ out:
 }
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
+static void reset_node_present_pages(pg_data_t *pgdat)
+{
+       struct zone *z;
+
+       for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
+               z->present_pages = 0;
+
+       pgdat->node_present_pages = 0;
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
 static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
 {
@@ -1096,6 +1107,21 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start)
        build_all_zonelists(pgdat, NULL);
        mutex_unlock(&zonelists_mutex);
 
+       /*
+        * zone->managed_pages is set to an approximate value in
+        * free_area_init_core(), which will cause
+        * /sys/device/system/node/nodeX/meminfo has wrong data.
+        * So reset it to 0 before any memory is onlined.
+        */
+       reset_node_managed_pages(pgdat);
+
+       /*
+        * When memory is hot-added, all the memory is in offline state. So
+        * clear all zones' present_pages because they will be updated in
+        * online_pages() and offline_pages().
+        */
+       reset_node_present_pages(pgdat);
+
        return pgdat;
 }
 
@@ -1699,7 +1725,7 @@ repeat:
        if (drain) {
                lru_add_drain_all();
                cond_resched();
-               drain_all_pages();
+               drain_all_pages(zone);
        }
 
        pfn = scan_movable_pages(start_pfn, end_pfn);
@@ -1721,7 +1747,7 @@ repeat:
        lru_add_drain_all();
        yield();
        /* drain pcp pages, this is synchronous. */
-       drain_all_pages();
+       drain_all_pages(zone);
        /*
         * dissolve free hugepages in the memory block before doing offlining
         * actually in order to make hugetlbfs's object counting consistent.