diff options
| author | Wei Yang <richard.weiyang@gmail.com> | 2026-06-22 02:24:03 +0000 |
|---|---|---|
| committer | Mike Rapoport (Microsoft) <rppt@kernel.org> | 2026-06-30 11:36:22 +0300 |
| commit | 7783dcd79ae9c4aa48bc47bd4275772445dc4b2a (patch) | |
| tree | 47fa7909aa1940255d9ffe92df91392fb5b0efbe | |
| parent | dc59e4fea9d83f03bad6bddf3fa2e52491777482 (diff) | |
| download | linux-next-7783dcd79ae9c4aa48bc47bd4275772445dc4b2a.tar.gz linux-next-7783dcd79ae9c4aa48bc47bd4275772445dc4b2a.zip | |
mm/mm_init: fix incorrect node_spanned_pages
Current node_spanned_pages is got as a summation of all zone's spanned page
in calculate_node_totalpages(). Generally this is good, but if we use
kernelcore=mirror, it is would be wrong.
Without kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x0
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x0
memory[0x2] [0x0000000100000000-0x00000001bfffffff], 0x00000000c0000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 1835007 totalpages: 1572733
With kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x2
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x2
memory[0x2] [0x0000000100000000-0x000000013fffffff], 0x0000000040000000 bytes on node 0 flags: 0x2
memory[0x3] [0x0000000140000000-0x00000001bfffffff], 0x0000000080000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Device empty
Movable zone start for each node
Node 0: 0x0000000140000000
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 2359295 totalpages: 1572733
The total range of memory on node 0 doesn't change, but the spanned_pages
becomes much larger.
The reason is when kernelcore=mirror is specified, the range of Zone Normal
and Zone Movable would overlap. So the overlapped range would be calculated
twice.
A wrong node_spanned_pages would effect defer_init(), since each
zone_end_pfn is less than pgdat_end_pfn().
As we already passed in node_start_pfn and node_end_pfn, fix this by get it
from (node_start_pfn - node_end_pfn) directly.
Fixes: 342332e6a925 ("mm/page_alloc.c: introduce kernelcore=mirror option")
Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Yuan Liu <yuan1.liu@intel.com>
Link: https://patch.msgid.link/20260622022403.16375-1-richard.weiyang@gmail.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
| -rw-r--r-- | mm/mm_init.c | 5 |
1 files changed, 2 insertions, 3 deletions
diff --git a/mm/mm_init.c b/mm/mm_init.c index 0f64909e8d20..0d2eb82fa068 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -1338,7 +1338,7 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat, unsigned long node_start_pfn, unsigned long node_end_pfn) { - unsigned long realtotalpages = 0, totalpages = 0; + unsigned long realtotalpages = 0; enum zone_type i; for (i = 0; i < MAX_NR_ZONES; i++) { @@ -1368,11 +1368,10 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat, zone->present_early_pages = real_size; #endif - totalpages += spanned; realtotalpages += real_size; } - pgdat->node_spanned_pages = totalpages; + pgdat->node_spanned_pages = node_end_pfn - node_start_pfn; pgdat->node_present_pages = realtotalpages; pr_debug("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages); } |
