]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
debugobject: Make it work with deferred page initialization - again
authorThomas Gleixner <tglx@kernel.org>
Sat, 7 Feb 2026 13:27:05 +0000 (14:27 +0100)
committerThomas Gleixner <tglx@kernel.org>
Tue, 10 Feb 2026 12:26:19 +0000 (13:26 +0100)
debugobjects uses __GFP_HIGH for allocations as it might be invoked
within locked regions. That worked perfectly fine until v6.18. It still
works correctly when deferred page initialization is disabled and works
by chance when no page allocation is required before deferred page
initialization has completed.

Since v6.18 allocations w/o a reclaim flag cause new_slab() to end up in
alloc_frozen_pages_nolock_noprof(), which returns early when deferred
page initialization has not yet completed. As the deferred page
initialization takes quite a while the debugobject pool is depleted and
debugobjects are disabled.

This can be worked around when PREEMPT_COUNT is enabled as that allows
debugobjects to add __GFP_KSWAPD_RECLAIM to the GFP flags when the context
is preemtible. When PREEMPT_COUNT is disabled the context is unknown and
the reclaim bit can't be set because the caller might hold locks which
might deadlock in the allocator.

In preemptible context the reclaim bit is harmless and not a performance
issue as that's usually invoked from slow path initialization context.

That makes debugobjects depend on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT.

Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock().")
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Link: https://patch.msgid.link/87pl6gznti.ffs@tglx
lib/Kconfig.debug
lib/debugobjects.c

index ba36939fda79bf890834b586c366a28acd434ef9..a874146ad828d5b1436521a49ccd084fb17a2b98 100644 (file)
@@ -723,6 +723,7 @@ source "mm/Kconfig.debug"
 
 config DEBUG_OBJECTS
        bool "Debug object operations"
+       depends on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT
        depends on DEBUG_KERNEL
        help
          If you say Y here, additional code will be inserted into the
index 89a1d6745dc2c63a3239cb17b6e1d525da6cc423..12f50de85b621a743a5b6f2638a308f6162c6fcc 100644 (file)
@@ -398,9 +398,26 @@ static void fill_pool(void)
 
        atomic_inc(&cpus_allocating);
        while (pool_should_refill(&pool_global)) {
+               gfp_t gfp = __GFP_HIGH | __GFP_NOWARN;
                HLIST_HEAD(head);
 
-               if (!kmem_alloc_batch(&head, obj_cache, __GFP_HIGH | __GFP_NOWARN))
+               /*
+                * Allow reclaim only in preemptible context and during
+                * early boot. If not preemptible, the caller might hold
+                * locks causing a deadlock in the allocator.
+                *
+                * If the reclaim flag is not set during early boot then
+                * allocations, which happen before deferred page
+                * initialization has completed, will fail.
+                *
+                * In preemptible context the flag is harmless and not a
+                * performance issue as that's usually invoked from slow
+                * path initialization context.
+                */
+               if (preemptible() || system_state < SYSTEM_SCHEDULING)
+                       gfp |= __GFP_KSWAPD_RECLAIM;
+
+               if (!kmem_alloc_batch(&head, obj_cache, gfp))
                        break;
 
                guard(raw_spinlock_irqsave)(&pool_lock);