Skip to contentSkip to conversation

New: WARNING at mm/memblock.c:904 __free_reserved_area(): "Cannot free reserved memory because of deferred initialization of the memory map" during housekeeping_init() at boot

Bug 221804 In review Andrew Morton 3 participants 5 messages Jul 28 – Aug 31 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]/

Andrew Morton

author maintainer
#1 lore raw

(switched to email. Please respond via emailed reply-to-all, not via the bugzilla web interface).

Quoted 21 lines · On Tue, 28 Jul 2026 15:52:54 +0000 [email protected] wrote:

https://bugzilla.kernel.org/show_bug.cgi?id=221804

Bug ID: 221804
Summary: WARNING at mm/memblock.c:904 __free_reserved_area():
"Cannot free reserved memory because of deferred initialization of the memory map" during housekeeping_init() at boot
Product: Memory Management
Version: 2.5
Hardware: All
OS: Linux
Status: NEW
Severity: normal
Priority: P3
Component: Other
Assignee: [email protected]
Reporter: [email protected]
Regression: No

Hello Kernel Team,

Quoted 7 lines

I notice this today:

...

[    0.075447] Dynamic Preempt: lazy
[    0.075489] ------------[ cut here ]------------
[    0.075490] Cannot free reserved memory because of deferred initialization

of the memory map

Thanks. I asked Gemini "what happened here" and the response was illuminating.

The bottom lines:

The Core Issue: Initialization Order Conflict

The kernel hit an order-of-operations conflict between memory setup and kernel parameter parsing:

CONFIG_DEFERRED_STRUCT_PAGE_INIT=y delays initializing struct page tracking structures for large pools of RAM until secondary CPUs come online (to speed up boot times on large systems).

housekeeping_init() runs very early during start_kernel(). It parses CPU isolation/housekeeping flags (isolcpus=, nohz_full=, rcu_nocbs=) and allocates temporary cpumask buffers in memblock. Once parsed, it tries to free those temporary buffers back to the memory pool using memblock_phys_free().

The Collision: memblock_phys_free() calls __free_reserved_area(), which requires valid struct page mappings. Because page initialization was deferred, __free_reserved_area() detects that the target memory's struct page maps aren't ready yet (at time 0.075s, whereas deferred init only finished around 0.325s).

As a safeguard, __free_reserved_area() issues a WARN() and refuses to free the pages.

Fix/Workaround:

Fix the nohz_full syntax on the command line (e.g., nohz_full=8-55,64-111).

To eliminate the warning entirely until fixed upstream, boot with deferred_init=off as a kernel parameter or disable CONFIG_DEFERRED_STRUCT_PAGE_INIT in the kernel build. Upstream, housekeeping_init() should either avoid early memblock freeing or use allocations that don't depend on fully initialized page maps.

I don't think this is very high priority.

#2 lore raw
Quoted 56 lines · Andrew Morton

(switched to email. Please respond via emailed reply-to-all, not via the bugzilla web interface).

Quoted 21 lines · On Tue, 28 Jul 2026 15:52:54 +0000 [email protected] wrote:

https://bugzilla.kernel.org/show_bug.cgi?id=221804

Bug ID: 221804
Summary: WARNING at mm/memblock.c:904 __free_reserved_area():
"Cannot free reserved memory because of deferred initialization of the memory map" during housekeeping_init() at boot
Product: Memory Management
Version: 2.5
Hardware: All
OS: Linux
Status: NEW
Severity: normal
Priority: P3
Component: Other
Assignee: [email protected]
Reporter: [email protected]
Regression: No

Hello Kernel Team,

Quoted 7 lines

I notice this today:

...

[    0.075447] Dynamic Preempt: lazy
[    0.075489] ------------[ cut here ]------------
[    0.075490] Cannot free reserved memory because of deferred initialization

of the memory map

Thanks. I asked Gemini "what happened here" and the response was illuminating.

The bottom lines:

The Core Issue: Initialization Order Conflict

The kernel hit an order-of-operations conflict between memory setup and kernel parameter parsing:

CONFIG_DEFERRED_STRUCT_PAGE_INIT=y delays initializing struct page tracking structures for large pools of RAM until secondary CPUs come online (to speed up boot times on large systems).

housekeeping_init() runs very early during start_kernel(). It parses CPU isolation/housekeeping flags (isolcpus=, nohz_full=, rcu_nocbs=) and allocates temporary cpumask buffers in memblock. Once parsed, it tries to free those temporary buffers back to the memory pool using memblock_phys_free().

Quoted 5 lines

The Collision: memblock_phys_free() calls __free_reserved_area(), which requires valid struct page mappings. Because page initialization was deferred, __free_reserved_area() detects that the target memory's struct page maps aren't ready yet (at time 0.075s, whereas deferred init only finished around 0.325s).

Just to add a bit of a human touch:

housekeeping_setup() allocates the masks from memblock when it parses the command line before mm_core_init().

housekeeping_init() reallocates them with kmalloc() to allow consistent kfree() afterwards and frees the memblock allocations.

And since housekeeping_init() happens after page allocator + slab init and before deferred_memmap_init() we can't reliably memblock_free() the memblock allocations.

Quoted 7 lines

As a safeguard, __free_reserved_area() issues a WARN() and refuses to free the pages.

Fix/Workaround:

Fix the nohz_full syntax on the command line (e.g., nohz_full=8-55,64-111).

I don't see how that will help.

Quoted 2 lines

To eliminate the warning entirely until fixed upstream, boot with deferred_init=off as a kernel parameter

Which does not exist :)

Quoted 1 line

or disable CONFIG_DEFERRED_STRUCT_PAGE_INIT in the kernel build.

This would work, but would cost in boot time on a machine with 128 GiB of RAM.

Quoted 2 lines

Upstream, housekeeping_init() should either avoid early memblock freeing

Presuming that houskeeping wants to keep the reallocation with kmalloc(), it should defer freeing to, say, some_initcall(housekeeping_late_init).

And housekeeping_setup() might want to memblock_alloc() enough memory for all the possible hk_type's once and than free that memory in an initcall.

Quoted 2 lines

or use allocations that don't depend on fully initialized page maps.

It's really not an option :)

Quoted 1 line

I don't think this is very high priority.

Signature · 2 lines
Sincerely yours,
Mike.
#3 lore raw

PATCH 1/1 sched/isolation: Defer freeing of the bootmem housekeeping cpumasks

In reply to Andrew Morton

housekeeping_setup() allocates the housekeeping cpumasks from memblock while parsing the command line, long before the page allocator exists. housekeeping_init() then reallocates them with kmalloc(), so that a later runtime update can free the old mask with kfree(), and releases the memblock allocations with memblock_free().

That release is not safe where it currently sits. housekeeping_init() is called from start_kernel() after mm_core_init(), so slab_is_available() is already true and memblock_phys_free() takes the __free_reserved_area() path. But it is still called long before page_alloc_init_late(), so with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y the deferred part of the memory map is not initialized yet, and __free_reserved_area() refuses to touch it:

Cannot free reserved memory because of deferred initialization of the memory map

  WARNING: mm/memblock.c:904 at __free_reserved_area+0xde/0xf0, CPU#0: swapper/0/0
  Call Trace:
   memblock_phys_free+0xe4/0x120
   housekeeping_init+0x149/0x170
   start_kernel+0x5b6/0x800
   x86_64_start_reservations+0x24/0x30
   x86_64_start_kernel+0xd7/0xe0
   common_startup_64+0x13e/0x151

The warning fires once per housekeeping type in use -- four splats on a 112-CPU two-socket machine booted with both isolcpus= and nohz_full= -- and taints the kernel with G W. No memory is actually lost either way:
a cpumask is much smaller than a page, so __free_reserved_area() has no whole page to hand back to the buddy allocator in the first place.

Record the bootmem masks instead and release them from a core_initcall, which runs after page_alloc_init_late() has initialized the deferred memory map. early_initcall() would still be too early: kernel_init_freeable() runs do_pre_smp_initcalls() before page_alloc_init_late().

Masks that housekeeping_init() did not manage to replace, because kmalloc() failed, are never recorded and therefore stay live, preserving the existing error behaviour.

---
Reproduced on a Dell PowerEdge R750 (2x Xeon Gold 6330, 112 CPUs, 2 NUMA nodes, 128 GiB) running v7.2-rc5 with PREEMPT_RT and CONFIG_DEFERRED_STRUCT_PAGE_INIT=y, booted with:

rcu_nocbs=8-55,64-111 nohz_full=managed_irq,nohz,domain,8-55,64-111 isolcpus=managed_irq,nohz,domain,8-55,64-111 kthread_cpus=0-3,56-59 irqaffinity=4-7,60-63 rcutree.kthread_prio=21

Four splats at boot without this patch, none with it. Also build-tested on x86_64 defconfig plus CONFIG_NO_HZ_FULL and CONFIG_DEFERRED_STRUCT_PAGE_INIT.

The bad memblock_free() has been there since 27c3a5967f05 in v7.0, but it only became visible in v7.1, when 59bd1d914bb5 ("memblock: warn when freeing reserved memory before memory map is initialized") added the WARN. Since nothing is actually leaked and the effect is a warning plus a G W taint, I did not Cc stable -- say the word if you would rather have it there.

I also considered Mike's second suggestion, of having housekeeping_setup() make a single memblock allocation covering all HK_TYPE_MAX masks and freeing that one region later. It touches more code for no additional benefit here, so I went with the simpler variant.

 kernel/sched/isolation.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
kernel/sched/isolation.c +23 -1
index ef152d401fe2..5c36e33bac50 100644
@@ -28,6 +28,17 @@ struct housekeeping {
 
 static struct housekeeping housekeeping;
 
+/*
+ * Bootmem cpumasks that housekeeping_init() has replaced with kmalloc()ed
+ * copies. They can't be released right there: housekeeping_init() runs once
+ * the page allocator and slab are up, but before page_alloc_init_late() has
+ * initialized the deferred part of the memory map, and memblock_free() then
+ * reaches __free_reserved_area(), which refuses to touch a memory map that
+ * isn't fully initialized yet. Record them instead and release them from a
+ * core_initcall, which runs after page_alloc_init_late().
+ */
+static struct cpumask *housekeeping_bootmem_masks[HK_TYPE_MAX] __initdata;
+
 bool housekeeping_enabled(enum hk_type type)
 {
 	return !!(READ_ONCE(housekeeping.flags) & BIT(type));
@@ -189,10 +200,21 @@ void __init housekeeping_init(void)
 		WARN_ON_ONCE(cpumask_empty(omask));
 		cpumask_copy(nmask, omask);
 		RCU_INIT_POINTER(housekeeping.cpumasks[type], nmask);
-		memblock_free(omask, cpumask_size());
+		housekeeping_bootmem_masks[type] = omask;
 	}
 }
 
+static int __init housekeeping_free_bootmem_masks(void)
+{
+	enum hk_type type;
+
+	for (type = 0; type < HK_TYPE_MAX; type++)
+		memblock_free(housekeeping_bootmem_masks[type], cpumask_size());
+
+	return 0;
+}
+core_initcall(housekeeping_free_bootmem_masks);
+
 static void __init housekeeping_setup_type(enum hk_type type,
 					   cpumask_var_t housekeeping_staging)
 {

base-commit: 2d2338c93da79b3bfe4b6099a931d9468d539952

Signature · 1 line
2.55.0
Acked-by on v1 1/1
#4 lore raw

Re: [PATCH] sched/isolation: Defer freeing of the bootmem housekeeping cpumasks

Quoted 22 lines · Ionut Nechita

housekeeping_setup() allocates the housekeeping cpumasks from memblock while parsing the command line, long before the page allocator exists. housekeeping_init() then reallocates them with kmalloc(), so that a later runtime update can free the old mask with kfree(), and releases the memblock allocations with memblock_free().

That release is not safe where it currently sits. housekeeping_init() is called from start_kernel() after mm_core_init(), so slab_is_available() is already true and memblock_phys_free() takes the __free_reserved_area() path. But it is still called long before page_alloc_init_late(), so with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y the deferred part of the memory map is not initialized yet, and __free_reserved_area() refuses to touch it:

Record the bootmem masks instead and release them from a core_initcall, which runs after page_alloc_init_late() has initialized the deferred memory map. early_initcall() would still be too early: kernel_init_freeable() runs do_pre_smp_initcalls() before page_alloc_init_late().

Masks that housekeeping_init() did not manage to replace, because kmalloc() failed, are never recorded and therefore stay live, preserving the existing error behaviour.

Quoted 5 lines

Some nits below.

Quoted 9 lines
---
 kernel/sched/isolation.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
kernel/sched/isolation.c +0 -0
index ef152d401fe2..5c36e33bac50 100644

kernel/sched/isolation.c struct housekeeping { · line 32

Quoted 5 lines
kernel/sched/isolation.c +2 -0
@@ -28,6 +28,17 @@ struct housekeeping {
 
 static struct housekeeping housekeeping;
 
+/*
+ * Bootmem cpumasks that housekeeping_init() has replaced with kmalloc()ed

Nit: s/has replaced/replaces

kernel/sched/isolation.c struct housekeeping { · line 38

Quoted 6 lines
kernel/sched/isolation.c +6 -0
+ * copies. They can't be released right there: housekeeping_init() runs once
+ * the page allocator and slab are up, but before page_alloc_init_late() has
+ * initialized the deferred part of the memory map, and memblock_free() then
+ * reaches __free_reserved_area(), which refuses to touch a memory map that
+ * isn't fully initialized yet. Record them instead and release them from a
+ * core_initcall, which runs after page_alloc_init_late().

And I'd split it into 3 paragraphs :)

- the first sentence
- description why that memory can't be released in housekeeping_init()
- Record them ...

Quoted 34 lines
kernel/sched/isolation.c +15 -1
+ */
+static struct cpumask *housekeeping_bootmem_masks[HK_TYPE_MAX] __initdata;
+
 bool housekeeping_enabled(enum hk_type type)
 {
 	return !!(READ_ONCE(housekeeping.flags) & BIT(type));
@@ -189,10 +200,21 @@ void __init housekeeping_init(void)
 		WARN_ON_ONCE(cpumask_empty(omask));
 		cpumask_copy(nmask, omask);
 		RCU_INIT_POINTER(housekeeping.cpumasks[type], nmask);
-		memblock_free(omask, cpumask_size());
+		housekeeping_bootmem_masks[type] = omask;
 	}
 }
 
+static int __init housekeeping_free_bootmem_masks(void)
+{
+	enum hk_type type;
+
+	for (type = 0; type < HK_TYPE_MAX; type++)
+		memblock_free(housekeeping_bootmem_masks[type], cpumask_size());
+
+	return 0;
+}
+core_initcall(housekeeping_free_bootmem_masks);
+
 static void __init housekeeping_setup_type(enum hk_type type,
 					   cpumask_var_t housekeeping_staging)
 {

base-commit: 2d2338c93da79b3bfe4b6099a931d9468d539952

Signature · 1 line
2.55.0
Signature · 2 lines
Sincerely yours,
Mike.
#5 lore raw

Re: [PATCH] sched/isolation: Defer freeing of the bootmem housekeeping cpumasks

Quoted 3 lines · Mike Rapoport

Some nits below.

Thanks for the Ack and for the comment nits, and sorry for the noise -- this patch is not needed.

The same problem was already fixed by:

2b58c749b8c5 ("sched/isolation: Defer freeing of cpumask memblock memory
to initcall")

from Waiman Long, written on 2026-07-01, applied by Peter to sched/urgent and merged in v7.3-rc1. It records the stale bootmem masks on an __initdata llist and releases them from a pure_initcall, which is initcall level 0 and therefore runs from do_initcalls() inside do_basic_setup(), after page_alloc_init_late(). I only noticed it now, while preparing the v2 -- I should have re-checked mainline before posting.

So please drop this one, there will be no v2.

I will close bug 221804 as RESOLVED/CODE_FIX pointing at 2b58c749b8c5.

Ionut