Merge branch 'slab/next' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / mm / memory_hotplug.c
index 133a4e1..489f235 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/firmware-map.h>
 #include <linux/stop_machine.h>
 #include <linux/hugetlb.h>
+#include <linux/memblock.h>
 
 #include <asm/tlbflush.h>
 
@@ -401,13 +402,12 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
 static int __meminit __add_section(int nid, struct zone *zone,
                                        unsigned long phys_start_pfn)
 {
-       int nr_pages = PAGES_PER_SECTION;
        int ret;
 
        if (pfn_valid(phys_start_pfn))
                return -EEXIST;
 
-       ret = sparse_add_one_section(zone, phys_start_pfn, nr_pages);
+       ret = sparse_add_one_section(zone, phys_start_pfn);
 
        if (ret < 0)
                return ret;
@@ -934,7 +934,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
        arg.nr_pages = nr_pages;
        node_states_check_changes_online(nr_pages, zone, &arg);
 
-       nid = page_to_nid(pfn_to_page(pfn));
+       nid = pfn_to_nid(pfn);
 
        ret = memory_notify(MEM_GOING_ONLINE, &arg);
        ret = notifier_to_errno(ret);
@@ -1043,17 +1043,23 @@ static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
 }
 
 
-/*
+/**
+ * try_online_node - online a node if offlined
+ *
  * called by cpu_up() to online a node without onlined memory.
  */
-int mem_online_node(int nid)
+int try_online_node(int nid)
 {
        pg_data_t       *pgdat;
        int     ret;
 
+       if (node_online(nid))
+               return 0;
+
        lock_memory_hotplug();
        pgdat = hotadd_new_pgdat(nid, 0);
        if (!pgdat) {
+               pr_err("Cannot online node %d due to NULL pgdat\n", nid);
                ret = -ENOMEM;
                goto out;
        }
@@ -1061,6 +1067,12 @@ int mem_online_node(int nid)
        ret = register_one_node(nid);
        BUG_ON(ret);
 
+       if (pgdat->node_zonelists->_zonerefs->zone == NULL) {
+               mutex_lock(&zonelists_mutex);
+               build_all_zonelists(NULL, NULL);
+               mutex_unlock(&zonelists_mutex);
+       }
+
 out:
        unlock_memory_hotplug();
        return ret;
@@ -1411,6 +1423,36 @@ static bool can_offline_normal(struct zone *zone, unsigned long nr_pages)
 }
 #endif /* CONFIG_MOVABLE_NODE */
 
+static int __init cmdline_parse_movable_node(char *p)
+{
+#ifdef CONFIG_MOVABLE_NODE
+       /*
+        * Memory used by the kernel cannot be hot-removed because Linux
+        * cannot migrate the kernel pages. When memory hotplug is
+        * enabled, we should prevent memblock from allocating memory
+        * for the kernel.
+        *
+        * ACPI SRAT records all hotpluggable memory ranges. But before
+        * SRAT is parsed, we don't know about it.
+        *
+        * The kernel image is loaded into memory at very early time. We
+        * cannot prevent this anyway. So on NUMA system, we set any
+        * node the kernel resides in as un-hotpluggable.
+        *
+        * Since on modern servers, one node could have double-digit
+        * gigabytes memory, we can assume the memory around the kernel
+        * image is also un-hotpluggable. So before SRAT is parsed, just
+        * allocate memory near the kernel image to try the best to keep
+        * the kernel away from hotpluggable memory.
+        */
+       memblock_set_bottom_up(true);
+#else
+       pr_warn("movable_node option not supported\n");
+#endif
+       return 0;
+}
+early_param("movable_node", cmdline_parse_movable_node);
+
 /* check which state of node_states will be changed when offline memory */
 static void node_states_check_changes_offline(unsigned long nr_pages,
                struct zone *zone, struct memory_notify *arg)