[PATCH 8/9] locking/lockdep: Shrink static list_entries array to early bootstrap buffer

Jim Cromie via B4 Relay <[email protected]>
Newsgroups org.freedesktop.lists.dri-devel,org.kernel.feeds.b4-sent,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kernel.vger.netdev,org.kernel.vger.netfilter-devel,org.kvack.linux-mm
Message-ID <[email protected]>
From: Jim Cromie <[email protected]>

Shrink the static compile-time list_entries[] array and its tracking
bitmap from MAX_LOCKDEP_ENTRIES (32,768 entries, ~1.31 MB BSS) down to
a 4096-entry early boot bootstrap buffer (~160 KB BSS).

During early boot before mem_init(), lockdep records initial spinlock
dependencies in the static bootstrap buffer. Once the buddy page
allocator is online, alloc_list_entry() seamlessly spills all subsequent
lock dependency allocations directly into lockdep_pool in 64KB direct-map
folios.

Adds a core_initcall telemetry hook (lockdep_boot_report) to log the
exact count of bootstrap entries consumed prior to buddy initialization.

Empirical boot telemetry confirms zero regressions and validates the
two-tier spillway on x86 SMP:
  - Pre-buddy watermark: 668/4096 bootstrap entries consumed (16.3%).
  - Post-buddy scaling: 5,058 total direct dependencies and 22,577
    indirect paths validated, with 962 entries operating dynamically
    inside lockdep_pool direct-map folios.

Reclaims ~1.15 MB of static unswappable kernel .bss memory (88% reduction)
while enabling unbounded lockdep scaling on dense NUMA/container workloads.

Signed-off-by: Jim Cromie <[email protected]>
---
 kernel/locking/lockdep.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index c8975c9282bb..5968a976bf8e 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -229,9 +229,11 @@ static inline int debug_locks_off_graph_unlock(void)
 	return ret;
 }
 
+#define BOOTSTRAP_LOCKDEP_ENTRIES 4096UL
+
 unsigned long nr_list_entries;
-static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
-static DECLARE_BITMAP(list_entries_in_use, MAX_LOCKDEP_ENTRIES);
+static struct lock_list list_entries[BOOTSTRAP_LOCKDEP_ENTRIES];
+static DECLARE_BITMAP(list_entries_in_use, BOOTSTRAP_LOCKDEP_ENTRIES);
 
 /*
  * All data structures here are protected by the global debug_lock.
@@ -6271,6 +6273,12 @@ static void remove_class_from_lock_chains(struct pending_free *pf,
 	}
 }
 
+static inline bool is_bootstrap_entry(const struct lock_list *entry)
+{
+	return entry >= list_entries &&
+	       entry < list_entries + ARRAY_SIZE(list_entries);
+}
+
 /*
  * Remove all references to a lock class. The caller must hold the graph lock.
  */
@@ -6287,26 +6295,30 @@ static void zap_class(struct pending_free *pf, struct lock_class *class)
 	list_for_each_entry_safe(entry, tmp, &class->locks_after, entry) {
 		list_for_each_entry_safe(other, other_tmp, &entry->links_to->locks_before, entry) {
 			if (other->links_to == class) {
-				__clear_bit(other - list_entries, list_entries_in_use);
+				if (is_bootstrap_entry(other))
+					__clear_bit(other - list_entries, list_entries_in_use);
 				nr_list_entries--;
 				list_del_rcu(&other->entry);
 				break;
 			}
 		}
-		__clear_bit(entry - list_entries, list_entries_in_use);
+		if (is_bootstrap_entry(entry))
+			__clear_bit(entry - list_entries, list_entries_in_use);
 		nr_list_entries--;
 		list_del_rcu(&entry->entry);
 	}
 	list_for_each_entry_safe(entry, tmp, &class->locks_before, entry) {
 		list_for_each_entry_safe(other, other_tmp, &entry->links_to->locks_after, entry) {
 			if (other->links_to == class) {
-				__clear_bit(other - list_entries, list_entries_in_use);
+				if (is_bootstrap_entry(other))
+					__clear_bit(other - list_entries, list_entries_in_use);
 				nr_list_entries--;
 				list_del_rcu(&other->entry);
 				break;
 			}
 		}
-		__clear_bit(entry - list_entries, list_entries_in_use);
+		if (is_bootstrap_entry(entry))
+			__clear_bit(entry - list_entries, list_entries_in_use);
 		nr_list_entries--;
 		list_del_rcu(&entry->entry);
 	}
@@ -6718,6 +6730,15 @@ void __init lockdep_init(void)
 	       sizeof(((struct task_struct *)NULL)->held_locks));
 }
 
+static int __init lockdep_boot_report(void)
+{
+	pr_info("lockdep: %lu/%lu bootstrap entries used before buddy init, folio_pool active\n",
+		min_t(unsigned long, nr_list_entries, ARRAY_SIZE(list_entries)),
+		ARRAY_SIZE(list_entries));
+	return 0;
+}
+core_initcall(lockdep_boot_report);
+
 static void
 print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
 		     const void *mem_to, struct held_lock *hlock)

-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.