summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2016-07-26 18:22:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 19:19:19 -0400
commit90cae1fe1c3540f791d5b8e025985fa5e699b2bb (patch)
treed1d8fc1dcc765e4264378ec94d42de9bb47ada9c /mm/page_alloc.c
parent48406ef897f48d1a189d73f8c8cd2ece0dc19e5e (diff)
mm/init: fix zone boundary creation
As a part of memory initialisation the architecture passes an array to free_area_init_nodes() which specifies the max PFN of each memory zone. This array is not necessarily monotonic (due to unused zones) so this array is parsed to build monotonic lists of the min and max PFN for each zone. ZONE_MOVABLE is special cased here as its limits are managed by the mm subsystem rather than the architecture. Unfortunately, this special casing is broken when ZONE_MOVABLE is the not the last zone in the zone list. The core of the issue is: if (i == ZONE_MOVABLE) continue; arch_zone_lowest_possible_pfn[i] = arch_zone_highest_possible_pfn[i-1]; As ZONE_MOVABLE is skipped the lowest_possible_pfn of the next zone will be set to zero. This patch fixes this bug by adding explicitly tracking where the next zone should start rather than relying on the contents arch_zone_highest_possible_pfn[]. Thie is low priority. To get bitten by this you need to enable a zone that appears after ZONE_MOVABLE in the zone_type enum. As far as I can tell this means running a kernel with ZONE_DEVICE or ZONE_CMA enabled, so I can't see this affecting too many people. I only noticed this because I've been fiddling with ZONE_DEVICE on powerpc and 4.6 broke my test kernel. This bug, in conjunction with the changes in Taku Izumi's kernelcore=mirror patch (d91749c1dda71) and powerpc being the odd architecture which initialises max_zone_pfn[] to ~0ul instead of 0 caused all of system memory to be placed into ZONE_DEVICE at boot, followed a panic since device memory cannot be used for kernel allocations. I've already submitted a patch to fix the powerpc specific bits, but I figured this should be fixed too. Link: http://lkml.kernel.org/r/1462435033-15601-1-git-send-email-oohall@gmail.com Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Cc: Anton Blanchard <anton@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mel Gorman <mgorman@techsingularity.net> 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.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8b3e1341b754..8129922a1504 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6467,15 +6467,18 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
6467 sizeof(arch_zone_lowest_possible_pfn)); 6467 sizeof(arch_zone_lowest_possible_pfn));
6468 memset(arch_zone_highest_possible_pfn, 0, 6468 memset(arch_zone_highest_possible_pfn, 0,
6469 sizeof(arch_zone_highest_possible_pfn)); 6469 sizeof(arch_zone_highest_possible_pfn));
6470 arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions(); 6470
6471 arch_zone_highest_possible_pfn[0] = max_zone_pfn[0]; 6471 start_pfn = find_min_pfn_with_active_regions();
6472 for (i = 1; i < MAX_NR_ZONES; i++) { 6472
6473 for (i = 0; i < MAX_NR_ZONES; i++) {
6473 if (i == ZONE_MOVABLE) 6474 if (i == ZONE_MOVABLE)
6474 continue; 6475 continue;
6475 arch_zone_lowest_possible_pfn[i] = 6476
6476 arch_zone_highest_possible_pfn[i-1]; 6477 end_pfn = max(max_zone_pfn[i], start_pfn);
6477 arch_zone_highest_possible_pfn[i] = 6478 arch_zone_lowest_possible_pfn[i] = start_pfn;
6478 max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]); 6479 arch_zone_highest_possible_pfn[i] = end_pfn;
6480
6481 start_pfn = end_pfn;
6479 } 6482 }
6480 arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0; 6483 arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
6481 arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0; 6484 arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;