Re: [PATCH] mm/compaction: Fix the incorrect hole in fast_isolate_freepages()

From: Mike Rapoport
Date: Thu May 21 2020 - 05:26:31 EST


Hi Baoquan,

On Thu, May 21, 2020 at 09:44:07AM +0800, Baoquan He wrote:
> Qian reported that a crash happened in compaction.
> http://lkml.kernel.org/r/8C537EB7-85EE-4DCF-943E-3CC0ED0DF56D@xxxxxx
>
V> LTP: starting swapping01 (swapping01 -i 5)
> page:ffffea0000aa0000 refcount:1 mapcount:0 mapping:000000002243743b index:0x0
> flags: 0x1fffe000001000(reserved)
> raw: 001fffe000001000 ffffea0000aa0008 ffffea0000aa0008 0000000000000000
> raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
> page dumped because: VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn))
> page_owner info is not present (never set?)
> ------------[ cut here ]------------
> kernel BUG at mm/page_alloc.c:533!

...

> After investigation, it turns out that this is introduced by commit of
> linux-next: commit f6edbdb71877 ("mm: memmap_init: iterate over memblock
> regions rather that check each PFN").
>
> After investigation, it turns out that this is introduced by commit of
> linux-next, the patch subject is:
> "mm: memmap_init: iterate over memblock regions rather that check each PFN".
>
> Qian added debugging code. The debugging log shows that the fault page is
> 0x2a800000. From the system e820 map which is pasted at bottom, the page
> is in e820 reserved range:
> BIOS-e820: [mem 0x0000000029ffe000-0x000000002a80afff] reserved
> And it's in section [0x28000000, 0x2fffffff]. In that secion, there are
> several usable ranges and some e820 reserved ranges.
>
> For this kind of e820 reserved range, it won't be added to memblock allocator.
> However, init_unavailable_mem() will initialize to add them into node 0,
> zone 0. Before that commit, later, memmap_init() will add e820 reserved
> ranges into the zone where they are contained, because it can pass
> the checking of early_pfn_valid() and early_pfn_in_nid(). In this case,
> the e820 reserved range where fault page 0x2a800000 is located is added
> into DMA32 zone. After that commit, the e820 reserved rgions are kept
> in node 0, zone 0, since we iterate over memblock regions to iniatialize
> in memmap_init() instead, their node and zone won't be changed.

I wonder why woudn't we add the reserved memory to memblock from the
very beginning...
I've tried to undestand why this was not done, but I couldn't find the
reasoning behind that.

Can you please try the below patch and see if it helps or, on the
contrary, breaks anything else :)

diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index c5399e80c59c..b0940c618ed9 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -1301,8 +1301,11 @@ void __init e820__memblock_setup(void)
if (end != (resource_size_t)end)
continue;

- if (entry->type == E820_TYPE_SOFT_RESERVED)
+ if (entry->type == E820_TYPE_SOFT_RESERVED ||
+ entry->type == E820_TYPE_RESERVED) {
+ memblock_add(entry->addr, entry->size);
memblock_reserve(entry->addr, entry->size);
+ }

if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN)
continue;

> Now, fast_isolate_freepages() will use min mark directly as the migration
> target if no page is found from buddy. However, the min mark is not checked
> carefully, it could be in e820 reserved range, and trigger the
> VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn)) when try to mark it
> as skip.
>
> Here, let's call pageblock_pfn_to_page() to get page of min_pfn, since it
> will do careful checks and return NULL if the pfn is not qualified.
>
> [ 0.000000] BIOS-provided physical RAM map:
> [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000008bfff] usable
> [ 0.000000] BIOS-e820: [mem 0x000000000008c000-0x000000000009ffff] reserved
> [ 0.000000] BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000028328fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000028329000-0x0000000028568fff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000028569000-0x0000000028d85fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000028d86000-0x0000000028ee5fff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000028ee6000-0x0000000029a04fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000029a05000-0x0000000029a08fff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000029a09000-0x0000000029ee4fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000029ee5000-0x0000000029ef2fff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000029ef3000-0x0000000029f22fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000029f23000-0x0000000029f23fff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000029f24000-0x0000000029f24fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000029f25000-0x0000000029f28fff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000029f29000-0x0000000029f29fff] ACPI NVS
> [ 0.000000] BIOS-e820: [mem 0x0000000029f2a000-0x0000000029f2bfff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000029f2c000-0x0000000029f2cfff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000029f2d000-0x0000000029f2ffff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000029f30000-0x0000000029ffdfff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000029ffe000-0x000000002a80afff] reserved
> [ 0.000000] BIOS-e820: [mem 0x000000002a80b000-0x000000002a80efff] ACPI NVS
> [ 0.000000] BIOS-e820: [mem 0x000000002a80f000-0x000000002a81ffff] reserved
> [ 0.000000] BIOS-e820: [mem 0x000000002a820000-0x000000002a822fff] ACPI NVS
> [ 0.000000] BIOS-e820: [mem 0x000000002a823000-0x0000000033a22fff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000033a23000-0x0000000033a32fff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000033a33000-0x0000000033a42fff] ACPI NVS
> [ 0.000000] BIOS-e820: [mem 0x0000000033a43000-0x0000000033a52fff] ACPI data
> [ 0.000000] BIOS-e820: [mem 0x0000000033a53000-0x0000000077ffffff] usable
> [ 0.000000] BIOS-e820: [mem 0x0000000078000000-0x000000008fffffff] reserved
> [ 0.000000] BIOS-e820: [mem 0x00000000fed80000-0x00000000fed80fff] reserved
> [ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000087effffff] usable
> [ 0.000000] BIOS-e820: [mem 0x000000087f000000-0x000000087fffffff] reserved
>
> Reported-by: Qian Cai <cai@xxxxxx>
> Signed-off-by: Baoquan He <bhe@xxxxxxxxxx>
> ---
> mm/compaction.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/mm/compaction.c b/mm/compaction.c
> index 67fd317f78db..9ce4cff4d407 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -1418,7 +1418,9 @@ fast_isolate_freepages(struct compact_control *cc)
> cc->free_pfn = highest;
> } else {
> if (cc->direct_compaction && pfn_valid(min_pfn)) {
> - page = pfn_to_page(min_pfn);
> + page = pageblock_pfn_to_page(min_pfn,
> + pageblock_end_pfn(min_pfn),
> + cc->zone);
> cc->free_pfn = min_pfn;
> }
> }
> --
> 2.17.2
>

--
Sincerely yours,
Mike.