summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Rapoport (Microsoft) <rppt@kernel.org>2026-08-07 11:45:58 +0300
committerMike Rapoport (Microsoft) <rppt@kernel.org>2026-08-07 11:45:58 +0300
commit697c969b9cb2d74e2f9fca7322fea1695f2f7e6e (patch)
tree598a16bb4c9a90738e1b6041ef99ccbc74874a31
parentdc59e4fea9d83f03bad6bddf3fa2e52491777482 (diff)
parent97090500d776c3f6d08e857e3a0a7cf092999094 (diff)
Merge branch 'fixes' into for-next
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--mm/memory_hotplug.c3
-rw-r--r--mm/mm_init.c28
3 files changed, 22 insertions, 11 deletions
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 7c9d66729c60..06c58cb05779 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -289,7 +289,7 @@ static inline void __remove_memory(u64 start, u64 size) {}
/* Default online_type (MMOP_*) when new memory blocks are added. */
extern enum mmop mhp_get_default_online_type(void);
extern void mhp_set_default_online_type(enum mmop online_type);
-extern void __ref free_area_init_core_hotplug(struct pglist_data *pgdat);
+int __ref free_area_init_core_hotplug(struct pglist_data *pgdat);
extern int __add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory(int nid, u64 start, u64 size, mhp_t mhp_flags);
extern int add_memory_resource(int nid, struct resource *resource,
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 7ac19fab2263..8b137328dcf0 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1263,7 +1263,8 @@ static pg_data_t *hotadd_init_pgdat(int nid)
pgdat = NODE_DATA(nid);
/* init node's zones as empty zones, we don't have any present pages.*/
- free_area_init_core_hotplug(pgdat);
+ if (free_area_init_core_hotplug(pgdat))
+ return NULL;
/*
* The node we allocated has no zone fallback lists. For avoiding
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 0f64909e8d20..37a425a14595 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);
}
@@ -1536,7 +1535,7 @@ void __init set_pageblock_order(void)
* NOTE: this function is only called during memory hotplug
*/
#ifdef CONFIG_MEMORY_HOTPLUG
-void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)
+int __ref free_area_init_core_hotplug(struct pglist_data *pgdat)
{
int nid = pgdat->node_id;
enum zone_type z;
@@ -1544,8 +1543,14 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)
pgdat_init_internals(pgdat);
- if (pgdat->per_cpu_nodestats == &boot_nodestats)
- pgdat->per_cpu_nodestats = alloc_percpu(struct per_cpu_nodestat);
+ if (pgdat->per_cpu_nodestats == &boot_nodestats) {
+ struct per_cpu_nodestat __percpu *p;
+
+ p = alloc_percpu(struct per_cpu_nodestat);
+ if (!p)
+ return -ENOMEM;
+ pgdat->per_cpu_nodestats = p;
+ }
/*
* Reset the nr_zones, order and highest_zoneidx before reuse.
@@ -1576,6 +1581,8 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)
zone->present_pages = 0;
zone_init_internals(zone, z, nid, 0);
}
+
+ return 0;
}
#endif
@@ -2207,10 +2214,13 @@ bool __init deferred_grow_zone(struct zone *zone, unsigned int order)
}
/*
- * There were no pages to initialize and free which means the zone's
- * memory map is completely initialized.
+ * The loop only tests spfn before entering an iteration, so on exit it
+ * may point up to a section past the end of the zone. When it does,
+ * the rest of the zone has already been handed to
+ * deferred_init_memmap_chunk() and nothing is left to initialize.
*/
- pgdat->first_deferred_pfn = nr_pages ? spfn : ULONG_MAX;
+ pgdat->first_deferred_pfn =
+ spfn < zone_end_pfn(zone) ? spfn : ULONG_MAX;
pgdat_resize_unlock(pgdat, &flags);