From: David Rientjes <[email protected]>
Adds a numa=possible=<N> command line option to set an additional N nodes
as being possible for memory hotplug. This set of possible nodes
controls nr_node_ids and the sizes of several dynamically allocated node
arrays.
This allows memory hotplug to create new nodes for newly added memory
rather than binding it to existing nodes.
The first use-case for this will be node hotplug emulation which will use
these possible nodes to create new nodes to test the memory hotplug
callbacks and surrounding memory hotplug code.
CC: Haicheng Li <[email protected]>
Signed-off-by: David Rientjes <[email protected]>
Signed-off-by: Shaohui Zheng <[email protected]>
---
Documentation/x86/x86_64/boot-options.txt | 4 ++++
arch/x86/mm/numa_64.c | 18 +++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -174,6 +174,10 @@ NUMA
If given as an integer, fills all system RAM with N fake nodes
interleaved over physical nodes.
+ numa=possible=<N>
+ Sets an additional N nodes as being possible for memory
+ hotplug.
+
ACPI
acpi=off Don't enable ACPI
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -33,6 +33,7 @@ s16 apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
int numa_off __initdata;
static unsigned long __initdata nodemap_addr;
static unsigned long __initdata nodemap_size;
+static unsigned long __initdata numa_possible_nodes;
/*
* Map cpu index to node index
@@ -611,7 +612,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
#ifdef CONFIG_NUMA_EMU
if (cmdline && !numa_emulation(start_pfn, last_pfn, acpi, k8))
- return;
+ goto out;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
@@ -619,14 +620,14 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
#ifdef CONFIG_ACPI_NUMA
if (!numa_off && acpi && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
last_pfn << PAGE_SHIFT))
- return;
+ goto out;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
#ifdef CONFIG_K8_NUMA
if (!numa_off && k8 && !k8_scan_nodes())
- return;
+ goto out;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
@@ -646,6 +647,15 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
numa_set_node(i, 0);
memblock_x86_register_active_regions(0, start_pfn, last_pfn);
setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
+out: __maybe_unused
+ for (i = 0; i < numa_possible_nodes; i++) {
+ int nid;
+
+ nid = first_unset_node(node_possible_map);
+ if (nid == MAX_NUMNODES)
+ break;
+ node_set(nid, node_possible_map);
+ }
}
unsigned long __init numa_free_all_bootmem(void)
@@ -675,6 +685,8 @@ static __init int numa_setup(char *opt)
if (!strncmp(opt, "noacpi", 6))
acpi_numa = -1;
#endif
+ if (!strncmp(opt, "possible=", 9))
+ numa_possible_nodes = simple_strtoul(opt + 9, NULL, 0);
return 0;
}
early_param("numa", numa_setup);
--
Thanks & Regards,
Shaohui
On Fri, 10 Dec 2010 15:31:21 +0800
[email protected] wrote:
> @@ -646,6 +647,15 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
> numa_set_node(i, 0);
> memblock_x86_register_active_regions(0, start_pfn, last_pfn);
> setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
> +out: __maybe_unused
hm, I didn't know you could do that with labels.
Does it work?
> + for (i = 0; i < numa_possible_nodes; i++) {
> + int nid;
> +
> + nid = first_unset_node(node_possible_map);
> + if (nid == MAX_NUMNODES)
> + break;
> + node_set(nid, node_possible_map);
> + }
> }
>
> unsigned long __init numa_free_all_bootmem(void)
On Wed, 22 Dec 2010, Andrew Morton wrote:
> > @@ -646,6 +647,15 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
> > numa_set_node(i, 0);
> > memblock_x86_register_active_regions(0, start_pfn, last_pfn);
> > setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
> > +out: __maybe_unused
>
> hm, I didn't know you could do that with labels.
>
> Does it work?
>
Yeah, it's equivalent to __attribute__((unused)) and according to the gcc
manual section 6.30:
In GNU C, an attribute specifier list may appear after the colon
following a label, other than a case or default label. The only
attribute it makes sense to use after a label is unused. This
feature is intended for code generated by programs which contains
labels that may be unused but which is compiled with ‘-Wall’. It
would not normally be appropriate to use in it human-written code,
though it could be useful in cases where the code that jumps to
the label is contained within an #ifdef conditional.
I used it because I knew I wouldn't get away with putting a label inside
an #ifdef :)
> > + for (i = 0; i < numa_possible_nodes; i++) {
> > + int nid;
> > +
> > + nid = first_unset_node(node_possible_map);
> > + if (nid == MAX_NUMNODES)
> > + break;
> > + node_set(nid, node_possible_map);
> > + }
> > }
> >
> > unsigned long __init numa_free_all_bootmem(void)