From: Jim Cromie <jim.cromie@gmail.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>, Will Deacon <will@kernel.org>,
Boqun Feng <boqun@kernel.org>, Waiman Long <longman@redhat.com>
Cc: linux-kernel@vger.kernel.org, Jim Cromie <jim.cromie@gmail.com>
Subject: [PATCH 8/8] lockdep: on debug_locks_off or OOM, recycle all slabs to buddy
Date: Wed, 26 Aug 2026 21:58:40 -0600 [thread overview]
Message-ID: <20260826-lockdep-memblock-v1-v1-8-e2db855391ec@gmail.com> (raw)
In-Reply-To: <20260826-lockdep-memblock-v1-v1-0-e2db855391ec@gmail.com>
If lockdep breaks, by assertion failure or for ENOMEM-ish reasons, we
can no longer use the graph-db. Since most of the graph-db is now
allocated from memblock_alloc() slabs, we can release them all back to
buddy, and hope that freeing ~1.5MB will help. (v7.2 has ~10MB tied up
in .bss).
0. Hook debug_locks_off() / print_lockdep_off() via an asynchronous
work item (lockdep_sacrifice_work) to release all held slabs back
to the buddy allocator via free_reserved_page() in process context.
1. Register an OOM notifier (lockdep_oom_nb) at late_initcall. If the
system encounters an out-of-memory emergency, lockdep sacrifices its
entire dynamic slab pool (1..8 MB of physical RAM), reporting freed
pages to the OOM killer to avoid terminating user processes.
2. Clear lockdep_slabs[] pointers and zero lockdep_nr_slabs under
graph_lock to seal off subsequent allocations.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
kernel/locking/lockdep.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index b6048e7c8b56..9f28530b2f1d 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -60,7 +60,9 @@
#include <linux/kasan.h>
#include <linux/mm.h>
#include <linux/memblock.h>
+#include <linux/oom.h>
#include <linux/reboot.h>
+#include <linux/workqueue.h>
#include <asm/sections.h>
@@ -638,6 +640,82 @@ static int verbose(struct lock_class *class)
return 0;
}
+/*
+ * Release all memblock slabs (used and unused) back to the buddy allocator
+ * when lockdep is disabled or during system OOM emergencies.
+ * Must run in process context (workqueue or OOM notifier).
+ */
+static unsigned int lockdep_release_slabs_to_buddy(void)
+{
+ unsigned int freed_slabs = 0;
+ unsigned int nr = lockdep_nr_slabs;
+ unsigned long flags;
+ unsigned int i;
+
+ if (!nr)
+ return 0;
+
+ /* Invalidate table bounds under graph_lock */
+ raw_local_irq_save(flags);
+ if (!graph_lock()) {
+ raw_local_irq_restore(flags);
+ return 0;
+ }
+ lockdep_nr_slabs = 0;
+ lockdep_slabs_used = 0;
+ graph_unlock();
+ raw_local_irq_restore(flags);
+
+ for (i = 0; i < nr; i++) {
+ struct page *page;
+ unsigned long p;
+
+ if (!lockdep_slabs[i])
+ continue;
+
+ page = virt_to_page(lockdep_slabs[i]);
+ for (p = 0; p < (LOCKDEP_SLAB_SIZE >> PAGE_SHIFT); p++)
+ free_reserved_page(page + p);
+
+ lockdep_slabs[i] = NULL;
+ freed_slabs++;
+ }
+
+ if (freed_slabs)
+ pr_info("lockdep: emergency sacrifice — released %u slabs (%u kB) to buddy allocator\n",
+ freed_slabs, (freed_slabs * LOCKDEP_SLAB_SIZE) / 1024);
+
+ return freed_slabs;
+}
+
+static void lockdep_sacrifice_work_fn(struct work_struct *work)
+{
+ lockdep_release_slabs_to_buddy();
+}
+static DECLARE_WORK(lockdep_sacrifice_work, lockdep_sacrifice_work_fn);
+
+static int lockdep_oom_notify(struct notifier_block *self,
+ unsigned long dummy, void *parm)
+{
+ unsigned long *freed = parm;
+ unsigned int freed_slabs;
+
+ if (!lockdep_nr_slabs)
+ return NOTIFY_OK;
+
+ /* Turn off lockdep before sacrificing tables */
+ debug_locks_off();
+ freed_slabs = lockdep_release_slabs_to_buddy();
+ if (freed && freed_slabs)
+ *freed += (freed_slabs * (LOCKDEP_SLAB_SIZE >> PAGE_SHIFT));
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block lockdep_oom_nb = {
+ .notifier_call = lockdep_oom_notify,
+};
+
static void print_lockdep_off(const char *bug_msg)
{
printk(KERN_DEBUG "%s\n", bug_msg);
@@ -645,6 +723,8 @@ static void print_lockdep_off(const char *bug_msg)
#ifdef CONFIG_LOCK_STAT
printk(KERN_DEBUG "Please attach the output of /proc/lock_stat to the bug report\n");
#endif
+ if (system_state >= SYSTEM_RUNNING)
+ schedule_work(&lockdep_sacrifice_work);
}
unsigned long nr_stack_trace_entries;
@@ -7105,6 +7185,7 @@ static int __init lockdep_post_init_trim(void)
lockdep_nr_slabs > used ? ((lockdep_nr_slabs - used) * 100) / used : 0,
freed_slabs, (freed_slabs * LOCKDEP_SLAB_SIZE) / 1024);
+ register_oom_notifier(&lockdep_oom_nb);
register_reboot_notifier(&lockdep_reboot_nb);
return 0;
}
--
2.55.0
next prev parent reply other threads:[~2026-08-27 3:58 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 3:58 [PATCH 0/8] lockdep: change 5 graph-db arrays to AofAs, fill from memblock pool Jim Cromie
2026-08-27 3:58 ` [PATCH 1/8] lockdep: Traverse adjacency lists directly in zap_class() Jim Cromie
2026-08-27 3:58 ` [PATCH 2/8] lockdep: Add chunked array infrastructure and embedded indices Jim Cromie
2026-08-27 3:58 ` [PATCH 3/8] lockdep: Pre-reserve early memblock slab pool for dynamic tables Jim Cromie
2026-08-27 3:58 ` [PATCH 4/8] lockdep: Convert 5 graph arrays to chunked tables backed by slab pool Jim Cromie
2026-08-27 3:58 ` [PATCH 5/8] lockdep: Fast-path power-of-2 tables with shift/mask indexing Jim Cromie
2026-08-27 3:58 ` [PATCH 6/8] lockdep: Free unused reservation slabs to buddy allocator at late boot Jim Cromie
2026-08-27 3:58 ` [PATCH 7/8] lockdep: Expose slab pool telemetry in /proc/lockdep_stats and initcalls Jim Cromie
2026-08-27 3:58 ` Jim Cromie [this message]
2026-08-27 6:46 ` [PATCH 0/8] lockdep: change 5 graph-db arrays to AofAs, fill from memblock pool Peter Zijlstra
2026-08-27 8:54 ` jim.cromie
2026-08-27 9:03 ` Peter Zijlstra
2026-08-27 18:40 ` jim.cromie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260826-lockdep-memblock-v1-v1-8-e2db855391ec@gmail.com \
--to=jim.cromie@gmail.com \
--cc=boqun@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=longman@redhat.com \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®