Commit fb01439c authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds

[PATCH] Allow an arch to expand node boundaries

Arch-independent zone-sizing determines the size of a node
(pgdat->node_spanned_pages) based on the physical memory that was
registered by the architecture.  However, when
CONFIG_MEMORY_HOTPLUG_RESERVE is set, the architecture expects that the
spanned_pages will be much larger and that mem_map will be allocated that
is used lated on memory hot-add.

This patch allows an architecture that sets CONFIG_MEMORY_HOTPLUG_RESERVE
to call push_node_boundaries() which will set the node beginning and end to
at *least* the requested boundary.

Cc: Dave Hansen <haveblue@us.ibm.com>
Cc: Andy Whitcroft <apw@shadowen.org>
Cc: Andi Kleen <ak@muc.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: "Keith Mannthey" <kmannth@gmail.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9c7cd687
...@@ -324,6 +324,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) ...@@ -324,6 +324,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
nd->start, nd->end); nd->start, nd->end);
e820_register_active_regions(node, nd->start >> PAGE_SHIFT, e820_register_active_regions(node, nd->start >> PAGE_SHIFT,
nd->end >> PAGE_SHIFT); nd->end >> PAGE_SHIFT);
push_node_boundaries(node, nd->start >> PAGE_SHIFT,
nd->end >> PAGE_SHIFT);
#ifdef RESERVE_HOTADD #ifdef RESERVE_HOTADD
if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) { if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) {
......
...@@ -970,6 +970,8 @@ extern void add_active_range(unsigned int nid, unsigned long start_pfn, ...@@ -970,6 +970,8 @@ extern void add_active_range(unsigned int nid, unsigned long start_pfn,
unsigned long end_pfn); unsigned long end_pfn);
extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn, extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
unsigned long new_end_pfn); unsigned long new_end_pfn);
extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn,
unsigned long end_pfn);
extern void remove_all_active_ranges(void); extern void remove_all_active_ranges(void);
extern unsigned long absent_pages_in_range(unsigned long start_pfn, extern unsigned long absent_pages_in_range(unsigned long start_pfn,
unsigned long end_pfn); unsigned long end_pfn);
......
...@@ -131,6 +131,10 @@ static unsigned long __initdata dma_reserve; ...@@ -131,6 +131,10 @@ static unsigned long __initdata dma_reserve;
int __initdata nr_nodemap_entries; int __initdata nr_nodemap_entries;
unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES];
unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES];
#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
#ifdef CONFIG_DEBUG_VM #ifdef CONFIG_DEBUG_VM
...@@ -2094,6 +2098,62 @@ void __init sparse_memory_present_with_active_regions(int nid) ...@@ -2094,6 +2098,62 @@ void __init sparse_memory_present_with_active_regions(int nid)
early_node_map[i].end_pfn); early_node_map[i].end_pfn);
} }
/**
* push_node_boundaries - Push node boundaries to at least the requested boundary
* @nid: The nid of the node to push the boundary for
* @start_pfn: The start pfn of the node
* @end_pfn: The end pfn of the node
*
* In reserve-based hot-add, mem_map is allocated that is unused until hotadd
* time. Specifically, on x86_64, SRAT will report ranges that can potentially
* be hotplugged even though no physical memory exists. This function allows
* an arch to push out the node boundaries so mem_map is allocated that can
* be used later.
*/
#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
void __init push_node_boundaries(unsigned int nid,
unsigned long start_pfn, unsigned long end_pfn)
{
printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n",
nid, start_pfn, end_pfn);
/* Initialise the boundary for this node if necessary */
if (node_boundary_end_pfn[nid] == 0)
node_boundary_start_pfn[nid] = -1UL;
/* Update the boundaries */
if (node_boundary_start_pfn[nid] > start_pfn)
node_boundary_start_pfn[nid] = start_pfn;
if (node_boundary_end_pfn[nid] < end_pfn)
node_boundary_end_pfn[nid] = end_pfn;
}
/* If necessary, push the node boundary out for reserve hotadd */
static void __init account_node_boundary(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
{
printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n",
nid, *start_pfn, *end_pfn);
/* Return if boundary information has not been provided */
if (node_boundary_end_pfn[nid] == 0)
return;
/* Check the boundaries and update if necessary */
if (node_boundary_start_pfn[nid] < *start_pfn)
*start_pfn = node_boundary_start_pfn[nid];
if (node_boundary_end_pfn[nid] > *end_pfn)
*end_pfn = node_boundary_end_pfn[nid];
}
#else
void __init push_node_boundaries(unsigned int nid,
unsigned long start_pfn, unsigned long end_pfn) {}
static void __init account_node_boundary(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn) {}
#endif
/** /**
* get_pfn_range_for_nid - Return the start and end page frames for a node * get_pfn_range_for_nid - Return the start and end page frames for a node
* @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned
...@@ -2121,6 +2181,9 @@ void __init get_pfn_range_for_nid(unsigned int nid, ...@@ -2121,6 +2181,9 @@ void __init get_pfn_range_for_nid(unsigned int nid,
printk(KERN_WARNING "Node %u active with no memory\n", nid); printk(KERN_WARNING "Node %u active with no memory\n", nid);
*start_pfn = 0; *start_pfn = 0;
} }
/* Push the node boundaries out if requested */
account_node_boundary(nid, start_pfn, end_pfn);
} }
/* /*
...@@ -2527,6 +2590,10 @@ void __init remove_all_active_ranges() ...@@ -2527,6 +2590,10 @@ void __init remove_all_active_ranges()
{ {
memset(early_node_map, 0, sizeof(early_node_map)); memset(early_node_map, 0, sizeof(early_node_map));
nr_nodemap_entries = 0; nr_nodemap_entries = 0;
#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn));
memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn));
#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
} }
/* Compare two active node_active_regions */ /* Compare two active node_active_regions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment