[PATCH for-next-fixes v2 3/5] mm/slab: call debug_locks and KCSAN checks in kfree_nolock()
From: Harry Yoo (Meta)
Date: Tue Nov 03 2026 - 10:02:48 EST
kfree_nolock() skips free hooks that may acquire spinlocks because it
can be called from any context. debug_check_no_locks_freed() and
__kcsan_check_access() are skipped as well.
However, they acquire a spinlock only when they report a bug.
debug_check_no_locks_freed() disables interrupts and walks
current->held_locks, and reaches printk only when a held lock is inside
the freed object. KCSAN takes report_lock only when it observes a race.
Just like KASAN, take the risk of potential deadlock for bug reporting.
Call debug_check_no_locks_freed() and __kcsan_check_access() regardless
of allow_spin.
Signed-off-by: Harry Yoo (Meta) <harry@xxxxxxxxxx>
---
mm/slub.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/mm/slub.c b/mm/slub.c
index 36e7bb93418a..48415f24e115 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2707,19 +2707,25 @@ bool slab_free_hook(struct kmem_cache *s, void *x, bool init,
kmsan_slab_free(s, x);
+ /*
+ * debug_locks, KCSAN, KASAN may acquire a spinlock to report a bug,
+ * but otherwise don't acquire any lock. Take the risk of deadlock
+ * for reporting.
+ */
+ debug_check_no_locks_freed(x, s->object_size);
+
+ /* Use KCSAN to help debug racy use-after-free. */
+ if (!still_accessible)
+ __kcsan_check_access(x, s->object_size,
+ KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ASSERT);
+
/* Hooks that acquire locks or kmalloc_nolock() skips alloc hook counterpart */
if (likely(allow_spin)) {
kmemleak_free_recursive(x, s->flags);
- debug_check_no_locks_freed(x, s->object_size);
if (!(s->flags & SLAB_DEBUG_OBJECTS))
debug_check_no_obj_freed(x, s->object_size);
- /* Use KCSAN to help debug racy use-after-free. */
- if (!still_accessible)
- __kcsan_check_access(x, s->object_size,
- KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ASSERT);
-
if (kfence_free(x))
return false;
}
@@ -2727,13 +2733,6 @@ bool slab_free_hook(struct kmem_cache *s, void *x, bool init,
/*
* Give KASAN a chance to notice an invalid free operation before we
* modify the object.
- *
- * If KASAN finds a bug it will do kasan_report_invalid_free() which
- * will call raw_spin_lock_irqsave() which is technically unsafe from
- * NMI, but take chance and report kernel bug. The sequence of
- * kasan_report_invalid_free() -> raw_spin_lock_irqsave() -> NMI
- * -> kfree_nolock() -> kasan_report_invalid_free() on the same CPU
- * is double buggy and deserves to deadlock.
*/
if (kasan_slab_pre_free(s, x))
return false;
--
2.54.0