linux/kernel/locking
Ingo Molnar 051f5d223d lockdep: Enable the printing of held locks of remote running tasks and print task CPU
Background:
==========

Currently lockdep does not print out the held locks of non-current
tasks that are running on some other CPU, due to the fact that
the held locks array is in flux and may be unreliable to print.

Syzkaller on the other hand found it that the analysis of locking
bugs is easier if we print this information too, because the
more locking information the merrier. In particular races are
bound to have multiple tasks running on different CPUs, and
the exclusion of their held locks information is unnecessarily
limiting.

So while it's still true that printing out their held locks
array is racy, it's not as bad as it seems.

There's 16 internal callers to lockdep_print_held_locks():

 - 14 callers call it with the current task, which should be
   safe out of box.

 - 1 caller, debug_show_all_locks(), calls it with RCU held,
   which should guarantee that 'p' cannot go away under us.

 - 1 caller, debug_show_held_locks(), exposes the internal API
   with the constraint that it should only be called by drivers
   or platform code if the task isn't actively running - we can
   assume that if it nevertheless does, it will be Their Problem™.

As for held locks being changed from under debug_show_held_locks(),
while the task cannot go away, so the held-locks array itself is
safe (although potentially non-stable), AFAICS the worst-case race
can be garbage printed out by print_lock(), not any actual crashes.

In particular:

        unsigned int class_idx = hlock->class_idx;

may be stale (belong to a lock that already got released on another
CPU), but it should still be a valid class index bound by
MAX_LOCKDEP_KEYS, and thus the lock_classes_in_use bitmap use
should be safe.

The other two accesses are ::acquire_ip and ::instance:

       printk(KERN_CONT "%px", hlock->instance);
       print_lock_name(hlock, lock);
       printk(KERN_CONT ", at: %pS\n", (void *)hlock->acquire_ip);

But both are printed out as pointers, so no risk of dereference
of a dangling pointer. We may print a garbage pointer.

Also note that the check itself doesn't protect debug_show_held_locks()
from printing garbage, as there's nothing that keeps a task from
becoming runnable a nanosecond after we've run the task_is_running()
check. In fact I'd argue that it's better to make this function
*more* racy, for the simple robustness reason that we absolutely
do not want it to crash even in the racy case.

TL;DR: it should be fine to print the held locks of running
tasks too, as long as we print out the information as well
that a task is running, so that users are aware of any
racy output.

Implementation:
==============

Implement that change.

Also re-flow the function and streamline the printout into
a single statement for all cases, which changes
the 'no locks held by' / '%d lock[s] held by' phrasing that had a
dependency on English spelling of plurals, to a uniform:

	locks held by bash/1234: %d

Which spells correctly for 0, 1 and higher values, and should also
be easier to parse both for humans and for scripts.

Finally, print out the last CPU a task has ran on. This is very
useful information for races and for locking bugs in particular.
This basically extends the 'on CPU#%d' message we print for
running tasks to all tasks we print.

Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Suggested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Tested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Boqun Feng <boqun@kernel.org>
Cc: Gary Guo <gary@garyguo.net>
Cc: Mark Brown <broonie@kernel.org>
Cc: Theodore Tso <tytso@mit.edu>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Waiman Long <longman@redhat.com>
Link: https://patch.msgid.link/akoeSIQGwqd9cZwd@gmail.com
2026-07-08 10:36:23 +02:00
..
irqflag-debug.c
lock_events_list.h bpf_res_spin_lock 2025-03-30 13:06:27 -07:00
lock_events.c locking/debug: Fix debugfs API return value checks to use IS_ERR() 2023-10-03 10:11:25 +02:00
lock_events.h locking/qspinlock: Always evaluate lockevent* non-event parameter once 2024-03-21 20:45:17 +01:00
lockdep_internals.h locking/lockdep: Change 'static const' variables to enum values 2025-07-14 21:57:29 -07:00
lockdep_proc.c locking/lockdep: Avoid struct return in lock_stats() 2025-07-14 21:57:20 -07:00
lockdep_states.h
lockdep.c lockdep: Enable the printing of held locks of remote running tasks and print task CPU 2026-07-08 10:36:23 +02:00
locktorture.c Convert remaining multi-line kmalloc_obj/flex GFP_KERNEL uses 2026-02-22 08:26:33 -08:00
Makefile locking/rwsem: Add context analysis 2026-03-08 11:06:53 +01:00
mcs_spinlock.h locking: Allow obtaining result of arch_mcs_spin_lock_contended 2025-03-19 08:03:04 -07:00
mutex-debug.c Scheduler changes for v7.1: 2026-04-14 13:33:36 -07:00
mutex.c Scheduler updates for v7.2: 2026-06-15 14:50:18 +05:30
mutex.h Scheduler changes for v7.1: 2026-04-14 13:33:36 -07:00
osq_lock.c locking/osq_lock: Use atomic_try_cmpxchg_release() in osq_unlock() 2024-10-25 10:01:50 +02:00
percpu-rwsem.c locking: Add contended_release tracepoint to sleepable locks 2026-06-11 13:41:25 +02:00
qrwlock.c locking: Add __lockfunc to slow path functions 2022-08-19 19:47:51 +02:00
qspinlock_paravirt.h locking/pvqspinlock: Convert fields of 'enum vcpu_state' to uppercase 2024-10-17 21:21:16 -07:00
qspinlock_stat.h
qspinlock.c locking: Move common qspinlock helpers to a private header 2025-03-19 08:02:29 -07:00
qspinlock.h locking: Move common qspinlock helpers to a private header 2025-03-19 08:02:29 -07:00
rtmutex_api.c Locking updates for v7.2: 2026-06-15 14:21:14 +05:30
rtmutex_common.h locking/rtmutex: Add context analysis 2026-03-08 11:06:53 +01:00
rtmutex.c Locking updates for v7.2: 2026-06-15 14:21:14 +05:30
rwbase_rt.c locking: Add contended_release tracepoint to sleepable locks 2026-06-11 13:41:25 +02:00
rwsem.c locking: Add contended_release tracepoint to sleepable locks 2026-06-11 13:41:25 +02:00
semaphore.c locking: Add contended_release tracepoint to sleepable locks 2026-06-11 13:41:25 +02:00
spinlock_debug.c locking/spinlock/debug: Fix data-race in do_raw_write_lock 2025-10-21 12:31:55 +02:00
spinlock_rt.c locking/rt: Fix the incorrect RCU protection in rt_spin_unlock() 2026-06-21 11:51:13 +02:00
spinlock.c locking: Add lock context annotations in the spinlock implementation 2026-03-16 13:16:50 +01:00
test-ww_mutex.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
ww_mutex.h sched/proxy: Remove PROXY_WAKING 2026-06-02 12:26:09 +02:00
ww_rt_mutex.c locking/rtmutex: Add context analysis 2026-03-08 11:06:53 +01:00