summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorTaku Izumi <izumi.taku@jp.fujitsu.com>2016-03-15 17:55:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 19:55:16 -0400
commit342332e6a925e9ed015e5465062c38d2b86ec8f9 (patch)
treea9aabc6010913a03258f07583d25c8f51e338bba /mm/page_alloc.c
parentd91749c1dda71a7030c054a5ab8dc5419bc6730b (diff)
mm/page_alloc.c: introduce kernelcore=mirror option
This patch extends existing "kernelcore" option and introduces kernelcore=mirror option. By specifying "mirror" instead of specifying the amount of memory, non-mirrored (non-reliable) region will be arranged into ZONE_MOVABLE. [akpm@linux-foundation.org: fix build with CONFIG_HAVE_MEMBLOCK_NODE_MAP=n] Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com> Tested-by: Sudeep Holla <sudeep.holla@arm.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Xishi Qiu <qiuxishi@huawei.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Steve Capper <steve.capper@linaro.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c114
1 files changed, 108 insertions, 6 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 0d20a19151a4..b8160b9d5e72 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -247,6 +247,7 @@ static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
247static unsigned long __initdata required_kernelcore; 247static unsigned long __initdata required_kernelcore;
248static unsigned long __initdata required_movablecore; 248static unsigned long __initdata required_movablecore;
249static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES]; 249static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
250static bool mirrored_kernelcore;
250 251
251/* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */ 252/* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
252int movable_zone; 253int movable_zone;
@@ -4491,6 +4492,9 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
4491 pg_data_t *pgdat = NODE_DATA(nid); 4492 pg_data_t *pgdat = NODE_DATA(nid);
4492 unsigned long pfn; 4493 unsigned long pfn;
4493 unsigned long nr_initialised = 0; 4494 unsigned long nr_initialised = 0;
4495#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
4496 struct memblock_region *r = NULL, *tmp;
4497#endif
4494 4498
4495 if (highest_memmap_pfn < end_pfn - 1) 4499 if (highest_memmap_pfn < end_pfn - 1)
4496 highest_memmap_pfn = end_pfn - 1; 4500 highest_memmap_pfn = end_pfn - 1;
@@ -4516,6 +4520,40 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
4516 if (!update_defer_init(pgdat, pfn, end_pfn, 4520 if (!update_defer_init(pgdat, pfn, end_pfn,
4517 &nr_initialised)) 4521 &nr_initialised))
4518 break; 4522 break;
4523
4524#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
4525 /*
4526 * if not mirrored_kernelcore and ZONE_MOVABLE exists,
4527 * range from zone_movable_pfn[nid] to end of each node
4528 * should be ZONE_MOVABLE not ZONE_NORMAL. skip it.
4529 */
4530 if (!mirrored_kernelcore && zone_movable_pfn[nid])
4531 if (zone == ZONE_NORMAL &&
4532 pfn >= zone_movable_pfn[nid])
4533 continue;
4534
4535 /*
4536 * check given memblock attribute by firmware which
4537 * can affect kernel memory layout.
4538 * if zone==ZONE_MOVABLE but memory is mirrored,
4539 * it's an overlapped memmap init. skip it.
4540 */
4541 if (mirrored_kernelcore && zone == ZONE_MOVABLE) {
4542 if (!r ||
4543 pfn >= memblock_region_memory_end_pfn(r)) {
4544 for_each_memblock(memory, tmp)
4545 if (pfn < memblock_region_memory_end_pfn(tmp))
4546 break;
4547 r = tmp;
4548 }
4549 if (pfn >= memblock_region_memory_base_pfn(r) &&
4550 memblock_is_mirror(r)) {
4551 /* already initialized as NORMAL */
4552 pfn = memblock_region_memory_end_pfn(r);
4553 continue;
4554 }
4555 }
4556#endif
4519 } 4557 }
4520 4558
4521 /* 4559 /*
@@ -4934,11 +4972,6 @@ static void __meminit adjust_zone_range_for_zone_movable(int nid,
4934 *zone_end_pfn = min(node_end_pfn, 4972 *zone_end_pfn = min(node_end_pfn,
4935 arch_zone_highest_possible_pfn[movable_zone]); 4973 arch_zone_highest_possible_pfn[movable_zone]);
4936 4974
4937 /* Adjust for ZONE_MOVABLE starting within this range */
4938 } else if (*zone_start_pfn < zone_movable_pfn[nid] &&
4939 *zone_end_pfn > zone_movable_pfn[nid]) {
4940 *zone_end_pfn = zone_movable_pfn[nid];
4941
4942 /* Check if this whole range is within ZONE_MOVABLE */ 4975 /* Check if this whole range is within ZONE_MOVABLE */
4943 } else if (*zone_start_pfn >= zone_movable_pfn[nid]) 4976 } else if (*zone_start_pfn >= zone_movable_pfn[nid])
4944 *zone_start_pfn = *zone_end_pfn; 4977 *zone_start_pfn = *zone_end_pfn;
@@ -5023,6 +5056,7 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
5023 unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type]; 5056 unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type];
5024 unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type]; 5057 unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
5025 unsigned long zone_start_pfn, zone_end_pfn; 5058 unsigned long zone_start_pfn, zone_end_pfn;
5059 unsigned long nr_absent;
5026 5060
5027 /* When hotadd a new node from cpu_up(), the node should be empty */ 5061 /* When hotadd a new node from cpu_up(), the node should be empty */
5028 if (!node_start_pfn && !node_end_pfn) 5062 if (!node_start_pfn && !node_end_pfn)
@@ -5034,7 +5068,39 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
5034 adjust_zone_range_for_zone_movable(nid, zone_type, 5068 adjust_zone_range_for_zone_movable(nid, zone_type,
5035 node_start_pfn, node_end_pfn, 5069 node_start_pfn, node_end_pfn,
5036 &zone_start_pfn, &zone_end_pfn); 5070 &zone_start_pfn, &zone_end_pfn);
5037 return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn); 5071 nr_absent = __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
5072
5073 /*
5074 * ZONE_MOVABLE handling.
5075 * Treat pages to be ZONE_MOVABLE in ZONE_NORMAL as absent pages
5076 * and vice versa.
5077 */
5078 if (zone_movable_pfn[nid]) {
5079 if (mirrored_kernelcore) {
5080 unsigned long start_pfn, end_pfn;
5081 struct memblock_region *r;
5082
5083 for_each_memblock(memory, r) {
5084 start_pfn = clamp(memblock_region_memory_base_pfn(r),
5085 zone_start_pfn, zone_end_pfn);
5086 end_pfn = clamp(memblock_region_memory_end_pfn(r),
5087 zone_start_pfn, zone_end_pfn);
5088
5089 if (zone_type == ZONE_MOVABLE &&
5090 memblock_is_mirror(r))
5091 nr_absent += end_pfn - start_pfn;
5092
5093 if (zone_type == ZONE_NORMAL &&
5094 !memblock_is_mirror(r))
5095 nr_absent += end_pfn - start_pfn;
5096 }
5097 } else {
5098 if (zone_type == ZONE_NORMAL)
5099 nr_absent += node_end_pfn - zone_movable_pfn[nid];
5100 }
5101 }
5102
5103 return nr_absent;
5038} 5104}
5039 5105
5040#else /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ 5106#else /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
@@ -5547,6 +5613,36 @@ static void __init find_zone_movable_pfns_for_nodes(void)
5547 } 5613 }
5548 5614
5549 /* 5615 /*
5616 * If kernelcore=mirror is specified, ignore movablecore option
5617 */
5618 if (mirrored_kernelcore) {
5619 bool mem_below_4gb_not_mirrored = false;
5620
5621 for_each_memblock(memory, r) {
5622 if (memblock_is_mirror(r))
5623 continue;
5624
5625 nid = r->nid;
5626
5627 usable_startpfn = memblock_region_memory_base_pfn(r);
5628
5629 if (usable_startpfn < 0x100000) {
5630 mem_below_4gb_not_mirrored = true;
5631 continue;
5632 }
5633
5634 zone_movable_pfn[nid] = zone_movable_pfn[nid] ?
5635 min(usable_startpfn, zone_movable_pfn[nid]) :
5636 usable_startpfn;
5637 }
5638
5639 if (mem_below_4gb_not_mirrored)
5640 pr_warn("This configuration results in unmirrored kernel memory.");
5641
5642 goto out2;
5643 }
5644
5645 /*
5550 * If movablecore=nn[KMG] was specified, calculate what size of 5646 * If movablecore=nn[KMG] was specified, calculate what size of
5551 * kernelcore that corresponds so that memory usable for 5647 * kernelcore that corresponds so that memory usable for
5552 * any allocation type is evenly spread. If both kernelcore 5648 * any allocation type is evenly spread. If both kernelcore
@@ -5806,6 +5902,12 @@ static int __init cmdline_parse_core(char *p, unsigned long *core)
5806 */ 5902 */
5807static int __init cmdline_parse_kernelcore(char *p) 5903static int __init cmdline_parse_kernelcore(char *p)
5808{ 5904{
5905 /* parse kernelcore=mirror */
5906 if (parse_option_str(p, "mirror")) {
5907 mirrored_kernelcore = true;
5908 return 0;
5909 }
5910
5809 return cmdline_parse_core(p, &required_kernelcore); 5911 return cmdline_parse_core(p, &required_kernelcore);
5810} 5912}
5811 5913