cpu/mem hotplug: enable CPUs online before local memory online
authorminskey guo <chaohong_guo@linux.intel.com>
Mon, 24 May 2010 21:32:41 +0000 (14:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 May 2010 15:07:00 +0000 (08:07 -0700)
Enable users to online CPUs even if the CPUs belongs to a numa node which
doesn't have onlined local memory.

The zonlists(pg_data_t.node_zonelists[]) of a numa node are created either
in system boot/init period, or at the time of local memory online.  For a
numa node without onlined local memory, its zonelists are not initialized
at present.  As a result, any memory allocation operations executed by
CPUs within this node will fail.  In fact, an out-of-memory error is
triggered when attempt to online CPUs before memory comes to online.

This patch tries to create zonelists for such numa nodes, so that the
memory allocation for this node can be fallback'ed to other nodes.

[akpm@linux-foundation.org: remove unneeded export]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: minskey guo<chaohong.guo@intel.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: Yasunori Goto <y-goto@jp.fujitsu.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/memory_hotplug.h
kernel/cpu.c
mm/memory_hotplug.c

index 35b07b773e6cbf90589b90b69897bc2043f7495d..864035fb8f8a83e547efbdd161093117bac94bc2 100644 (file)
@@ -202,6 +202,7 @@ static inline int is_mem_section_removable(unsigned long pfn,
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+extern int mem_online_node(int nid);
 extern int add_memory(int nid, u64 start, u64 size);
 extern int arch_add_memory(int nid, u64 start, u64 size);
 extern int remove_memory(u64 start, u64 size);
index 545777574779da71ef8e3fcc3935e0e41fa266ca..a3fbcc0a0abc15976dc78423a985a6c522180c18 100644 (file)
@@ -326,6 +326,12 @@ out_notify:
 int __cpuinit cpu_up(unsigned int cpu)
 {
        int err = 0;
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+       int nid;
+       pg_data_t       *pgdat;
+#endif
+
        if (!cpu_possible(cpu)) {
                printk(KERN_ERR "can't online cpu %d because it is not "
                        "configured as may-hotadd at boot time\n", cpu);
@@ -336,6 +342,25 @@ int __cpuinit cpu_up(unsigned int cpu)
                return -EINVAL;
        }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+       nid = cpu_to_node(cpu);
+       if (!node_online(nid)) {
+               err = mem_online_node(nid);
+               if (err)
+                       return err;
+       }
+
+       pgdat = NODE_DATA(nid);
+       if (!pgdat) {
+               printk(KERN_ERR
+                       "Can't online cpu %d due to NULL pgdat\n", cpu);
+               return -ENOMEM;
+       }
+
+       if (pgdat->node_zonelists->_zonerefs->zone == NULL)
+               build_all_zonelists();
+#endif
+
        cpu_maps_update_begin();
 
        if (cpu_hotplug_disabled) {
index be211a582930d87bba2f959e2729399e364f6ae9..85eb4d342ac5010ccc0997be9a251d20cb82bb50 100644 (file)
@@ -482,6 +482,29 @@ static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
 }
 
 
+/*
+ * called by cpu_up() to online a node without onlined memory.
+ */
+int mem_online_node(int nid)
+{
+       pg_data_t       *pgdat;
+       int     ret;
+
+       lock_system_sleep();
+       pgdat = hotadd_new_pgdat(nid, 0);
+       if (pgdat) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       node_set_online(nid);
+       ret = register_one_node(nid);
+       BUG_ON(ret);
+
+out:
+       unlock_system_sleep();
+       return ret;
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
 int __ref add_memory(int nid, u64 start, u64 size)
 {