[PATCH] mm: add missing alloc_percpu() NULL check in hotplug init
Hongfu Li <[email protected]>
| Newsgroups | org.kernel.vger.linux-cxl,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
From: Hongfu Li <[email protected]> No NULL check is done for alloc_percpu() when initializing per-CPU nodestats. Allocation failure leads to NULL pointer dereference during later memset. Make function return int, check alloc_percpu() result and return -ENOMEM on error. The caller chain already propagates this error correctly. Signed-off-by: Hongfu Li <[email protected]> --- include/linux/memory_hotplug.h | 2 +- mm/memory_hotplug.c | 3 ++- mm/mm_init.c | 14 +++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 7c9d66729c60..f04b915678db 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); +extern 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..24770947a66f 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -1536,7 +1536,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 +1544,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 *new; + + new = alloc_percpu(struct per_cpu_nodestat); + if (!new) + return -ENOMEM; + pgdat->per_cpu_nodestats = new; + } /* * Reset the nr_zones, order and highest_zoneidx before reuse. @@ -1576,6 +1582,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 -- 2.54.0