Re: [PATCH 1/1] mm: compaction: avoid fast_isolate_around() to set pageblock_skip on reserved pages

From: Andrea Arcangeli
Date: Thu Dec 03 2020 - 01:24:45 EST


On Wed, Dec 02, 2020 at 07:39:23PM +0200, Mike Rapoport wrote:
> Hmm, do you have any logs? It worked on my box and with various memory
> configurations in qemu.

It crashes in reserve_bootmem_region so no logs at all since the
serial console isn't active yet.

> I believe that the proper solution would be to have all the memory
> reserved by the firmware added to memblock.memory, like all other
> architectures do, but I'm not sure if we can easily and reliably
> determine what of E820 reserved types are actually backed by RAM.
> So this is not feasible as a short term solution.
>
> My patch [1], though, is an immediate improvement and I think it's worth
> trying to fix off-by-one's that prevent your system from booting.
>
> [1] https://lore.kernel.org/lkml/20201201181502.2340-1-rppt@xxxxxxxxxx

Yes that's the patch I applied.

Relevant points after debugging:

1) can you try again with DEBUG_VM=y?

2) DEBUG_VM=y already enforces the memset(page, 0xff, sizeof(struct
page)) on all struct pages allocated, exactly I was suggesting to
do in the previous email. I wonder why we're not doing that even
with DEBUG_VM=n, perhaps it's too slow for TiB systems. See
page_init_poison().

3) given 2), your patch below by deleting "0,0" initialization
achieves the debug feature to keep PagePoison forever on all
uninitialized pages, imagine PagePoison is really
NO_NODEID/NO_ZONEID and doesn't need handling other than a crash.

- __init_single_page(pfn_to_page(pfn), pfn, 0, 0);

4) because of the feature in 3) I now hit the PagePoison VM_BUG_ON
because pfn 0 wasn't initialized when reserve_bootmem_region tries
to call __SetPageReserved on a PagePoison page.

5) pfn 0 is the classical case where pfn 0 is in a reserved zone in
memblock.reserve that doesn't overlap any memblock.memory zone.

The memblock_start_of_DRAM moves the start of the DMA zone above
the pfn 0, so then pfn 0 already ends up in the no zone land David
mentioned where it's not trivial to decide to give it a zoneid if
it's not even spanned in the zone.

Not just the zoneid, there's not even a nid.

So we have a pfn with no zoneid, and no nid, and not part of the
zone ranges, not part of the nid ranges not part of the
memory.memblock.

We can't really skip the initialization of the the pfn 0, it has to
get the zoneid 0 treatment or if pfn 1 ends up in compaction code,
we'd crash again. (although we'd crash with a nice PagePoison(page)
== true behavior)

The below fixes the issue and it boots fine again and the compaction
crash should be solved with both patches applied.

DMA zone_start_pfn 0 zone_end_pfn() 4096 contiguous 1
DMA32 zone_start_pfn 4096 zone_end_pfn() 524252 contiguous 1
Normal zone_start_pfn 0 zone_end_pfn() 0 contiguous 0
Movable zone_start_pfn 0 zone_end_pfn() 0 contiguous 0

500246 0x7a216000 0x1fff000000001000 reserved True pfn_valid True
500247 0x7a217000 0x1fff000000000000 reserved False pfn_valid True
500248 0x7a218000 0x1fff000000000000 reserved False pfn_valid True

==== quote from previous email ====
73a6e474cb376921a311786652782155eac2fdf0 this changed it:

DMA zone_start_pfn 1 zone_end_pfn() 4096 contiguous 1
DMA32 zone_start_pfn 4096 zone_end_pfn() 524252 contiguous 0
Normal zone_start_pfn 0 zone_end_pfn() 0 contiguous 0
Movable zone_start_pfn 0 zone_end_pfn() 0 contiguous 0

500246 0x7a216000 0xfff000000001000 reserved True
500247 0x7a217000 0x1fff000000000000 reserved False
500248 0x7a218000 0x1fff000000010200 reserved False ]
==== quote from previous email ====