Commit 414989d2 authored by Oliver O'Halloran's avatar Oliver O'Halloran Committed by Willy Tarreau

mm/init: fix zone boundary creation

commit 90cae1fe upstream.

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 (d91749c1) 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.comSigned-off-by: default avatarOliver 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
parent 5765ee44
...@@ -5060,15 +5060,18 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn) ...@@ -5060,15 +5060,18 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
sizeof(arch_zone_lowest_possible_pfn)); sizeof(arch_zone_lowest_possible_pfn));
memset(arch_zone_highest_possible_pfn, 0, memset(arch_zone_highest_possible_pfn, 0,
sizeof(arch_zone_highest_possible_pfn)); sizeof(arch_zone_highest_possible_pfn));
arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
arch_zone_highest_possible_pfn[0] = max_zone_pfn[0]; start_pfn = find_min_pfn_with_active_regions();
for (i = 1; i < MAX_NR_ZONES; i++) {
for (i = 0; i < MAX_NR_ZONES; i++) {
if (i == ZONE_MOVABLE) if (i == ZONE_MOVABLE)
continue; continue;
arch_zone_lowest_possible_pfn[i] =
arch_zone_highest_possible_pfn[i-1]; end_pfn = max(max_zone_pfn[i], start_pfn);
arch_zone_highest_possible_pfn[i] = arch_zone_lowest_possible_pfn[i] = start_pfn;
max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]); arch_zone_highest_possible_pfn[i] = end_pfn;
start_pfn = end_pfn;
} }
arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0; arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0; arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;
......
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