[PATCH] mm/page_alloc.c: Add unavailable ranges into memblock

From: Baoquan He
Date: Fri May 22 2020 - 02:36:13 EST


These unavailable ranges shares the same section with the usable range
in boot memory, e.g the firmware reserved ranges, and holes.

Previously, they are added into node 0, zone 0 in function
init_unavailable_range(), and marked as Reserved. Later, in function
memmap_init(), they will be added to appropriate node and zone, where
they are covered.

However, after the patchset ("mm: rework free_area_init*() funcitons")
is applied, we change to iterate over memblock regions. These unavailable
ranges are skipped, and the node and zone adjustment won't be done any
more as the old code did. This cause a crash in compaction which is triggered
by VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn)).

So let's add these unavailable ranges into memblock and reserve them
in init_unavailable_range() instead. With this change, they will be added
into appropriate node and zone in memmap_init(), and initialized in
reserve_bootmem_region() just like any other memblock reserved regions.

Signed-off-by: Baoquan He <bhe@xxxxxxxxxx>
---
mm/page_alloc.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 603187800628..3973b5fdfe3f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6925,7 +6925,7 @@ static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn)
static void __init init_unavailable_mem(void)
{
phys_addr_t start, end;
- u64 i, pgcnt;
+ u64 i, pgcnt, size;
phys_addr_t next = 0;

/*
@@ -6934,9 +6934,11 @@ static void __init init_unavailable_mem(void)
pgcnt = 0;
for_each_mem_range(i, &memblock.memory, NULL,
NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, NULL) {
- if (next < start)
- pgcnt += init_unavailable_range(PFN_DOWN(next),
- PFN_UP(start));
+ if (next < start) {
+ size = PFN_UP(start) - PFN_DOWN(next);
+ memblock_add(PFN_DOWN(next), size);
+ memblock_reserve(PFN_DOWN(next), size);
+ }
next = end;
}

@@ -6947,8 +6949,11 @@ static void __init init_unavailable_mem(void)
* considered initialized. Make sure that memmap has a well defined
* state.
*/
- pgcnt += init_unavailable_range(PFN_DOWN(next),
- round_up(max_pfn, PAGES_PER_SECTION));
+ size = round_up(max_pfn, PAGES_PER_SECTION) - PFN_DOWN(next);
+ if (size) {
+ memblock_add(PFN_DOWN(next), size);
+ memblock_reserve(PFN_DOWN(next), size);
+ }

/*
* Struct pages that do not have backing memory. This could be because
--
2.17.2