linux/kernel
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
..
bpf bpf: Prefer dirty packs for eBPF allocations 2026-07-01 10:34:41 +02:00
cgroup cgroup: Changes for v7.2 2026-06-17 12:03:56 +01:00
configs slab: support for compiler-assisted type-based slab cache partitioning 2026-05-14 10:44:09 +02:00
debug kgdb: update outdated references to kgdb_wait() 2026-04-21 16:41:54 +01:00
dma dma-mapping updates for Linux 7.2: 2026-06-17 12:20:21 -07:00
entry futex: Provide infrastructure to plug the non contended robust futex unlock race 2026-06-03 11:38:52 +02:00
events perf/core: Detach event groups during remove_on_exec 2026-07-02 13:21:48 +02:00
futex futex/requeue: Revert "Prevent NULL pointer dereference in remove_waiter() on self-deadlock"" 2026-07-02 22:14:08 +02:00
gcov Convert more 'alloc_obj' cases to default GFP_KERNEL arguments 2026-02-21 20:03:00 -08:00
irq genirq/msi: Correct CONFIG_PCI_MSI_ARCH_FALLBACKS macro name in comment 2026-06-22 22:32:01 +02:00
kcsan kcsan: test: Adjust "expect" allocation type for kmalloc_obj 2026-02-26 09:54:08 -08:00
livepatch Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
liveupdate liveupdate: Remove limit on the number of files per session 2026-06-03 21:15:46 +03:00
locking lockdep: Enable the printing of held locks of remote running tasks and print task CPU 2026-07-08 10:36:23 +02:00
module module: decompress: check return value of module_extend_max_pages() 2026-06-04 16:37:32 +00:00
power mm.git review status for mm-hotfixes-stable..mm-stable 2026-06-19 10:14:34 -07:00
printk printk: fix typos in comments 2026-06-02 15:36:06 +02:00
rcu Updates for the NOHZ subsystem: 2026-06-15 13:48:52 +05:30
sched Power management fixes for 7.2-rc1 2026-06-26 13:14:18 -07:00
time time: Fix off-by-one in compat settimeofday() usec validation 2026-06-22 13:20:20 +02:00
trace Probes fixes for v7.2-rc1: 2026-06-30 17:50:44 -10:00
unwind Convert more 'alloc_obj' cases to default GFP_KERNEL arguments 2026-02-21 20:03:00 -08:00
.gitignore kheaders: rebuild kheaders_data.tar.xz when a file is modified within a minute 2025-06-24 20:30:37 +09:00
acct.c fs: move SB_I_USERNS_VISIBLE to FS_USERNS_MOUNT_RESTRICTED 2026-05-11 23:13:01 +02:00
async.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
audit_fsnotify.c audit: fix recursive locking deadlock in audit_dupe_exe() 2026-05-27 19:15:34 -04:00
audit_tree.c audit: use 'unsigned int' instead of 'unsigned' 2026-05-26 17:15:30 -04:00
audit_watch.c audit: fix recursive locking deadlock in audit_dupe_exe() 2026-05-27 19:15:34 -04:00
audit.c audit/stable-7.2 PR 20260615 2026-06-17 12:55:09 +01:00
audit.h audit: fix recursive locking deadlock in audit_dupe_exe() 2026-05-27 19:15:34 -04:00
auditfilter.c audit: fix recursive locking deadlock in audit_dupe_exe() 2026-05-27 19:15:34 -04:00
auditsc.c audit/stable-7.2 PR 20260615 2026-06-17 12:55:09 +01:00
backtracetest.c
bounds.c x86/asm: Remove ANNOTATE_DATA_SPECIAL usage 2025-12-03 16:53:19 +01:00
capability.c capability: Remove unused has_capability 2025-03-07 22:03:09 -06:00
cfi.c cfi: Move BPF CFI types and helpers to generic code 2025-07-31 18:23:53 -07:00
compat.c
configs.c
context_tracking.c context_tracking: Remove rcu_task_trace_heavyweight_{enter,exit}() 2026-01-01 16:39:46 +08:00
cpu_pm.c syscore: Pass context data to callbacks 2025-11-14 10:01:52 +01:00
cpu.c Misc CPU hotplug fixes: 2026-06-23 16:43:24 -07:00
crash_core_test.c crash: add KUnit tests for crash_exclude_mem_range 2025-09-13 17:32:55 -07:00
crash_core.c kernel/crash: remove inclusion of crypto/sha1.h 2026-03-27 21:19:46 -07:00
crash_dump_dm_crypt.c crash_dump/dm-crypt: don't print in arch-specific code 2026-04-02 23:36:24 -07:00
crash_reserve.c kernel/crash: remove inclusion of crypto/sha1.h 2026-03-27 21:19:46 -07:00
cred.c exec_state: relocate dumpable information 2026-05-26 11:02:01 +02:00
delayacct.c delayacct: fix uapi timespec64 definition 2026-02-08 00:13:32 -08:00
dma.c
elfcorehdr.c
exec_domain.c
exec_state.c exec_state: relocate dumpable information 2026-05-26 11:02:01 +02:00
exit.c Scheduler updates for v7.2: 2026-06-15 14:50:18 +05:30
exit.h
extable.c
fail_function.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
fork.c bpf,fork: wipe ->bpf_storage before bailouts that access it 2026-06-29 15:08:23 -07:00
freezer.c freezer: Clarify that only cgroup1 freezer uses PM freezer 2025-10-30 20:10:27 +01:00
gen_kheaders.sh kheaders: make it possible to override TAR 2025-08-06 10:23:36 +09:00
groups.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
hung_task.c hung_task: explicitly report I/O wait state in log output 2026-03-27 21:19:40 -07:00
iomem.c mm/memremap: Pass down MEMREMAP_* flags to arch_memremap_wb() 2025-02-21 15:05:38 +01:00
irq_work.c irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT 2026-05-11 16:28:04 +02:00
jump_label.c jump_label: use ATOMIC_INIT() for initialization of .enabled 2026-03-16 13:16:48 +01:00
kallsyms_internal.h kallsyms: Get rid of kallsyms relative base 2026-01-22 15:58:22 -07:00
kallsyms_selftest.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
kallsyms_selftest.h
kallsyms.c mm.git review status for linus..mm-nonmm-stable 2026-02-12 12:13:01 -08:00
kcmp.c kcmp: improve performance adding an unlikely hint to task comparisons 2025-02-21 10:25:33 +01:00
Kconfig.freezer
Kconfig.hz kernel: Fix "select" wording on HZ_250 description 2025-02-21 09:20:30 +01:00
Kconfig.kexec liveupdate: kho: move to kernel/liveupdate 2025-11-27 14:24:33 -08:00
Kconfig.locks
Kconfig.preempt sched: Further restrict the preemption modes 2026-01-08 12:43:57 +01:00
kcov.c kcov: use WRITE_ONCE() for selftest mode stores 2026-06-04 14:49:26 -07:00
kexec_core.c liveupdate: skip serialization for context-preserving kexec 2026-06-01 09:19:38 +03:00
kexec_elf.c kexec: initialize ELF lowest address to ULONG_MAX 2025-03-16 22:30:47 -07:00
kexec_file.c kexec: derive purgatory entry from symbol 2026-01-31 16:16:07 -08:00
kexec_internal.h kexec: enable CMA based contiguous allocation 2025-08-02 12:01:38 -07:00
kexec.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
kheaders.c kheaders: Simplify attribute through __BIN_ATTR_SIMPLE_RO() 2024-12-24 09:46:49 +01:00
kprobes.c kprobes: Remove unneeded warnings from __arm_kprobe_ftrace() 2026-03-13 23:15:26 +09:00
kstack_erase.c sysctl: remove __user qualifier from stack_erasing_sysctl buffer argument 2025-11-27 15:44:53 +01:00
ksyms_common.c
ksysfs.c kernel: ksysfs: initialize kernel_kobj earlier 2026-04-03 19:39:52 +02:00
kthread.c exec_state: relocate dumpable information 2026-05-26 11:02:01 +02:00
latencytop.c treewide: const qualify ctl_tables where applicable 2025-01-28 13:48:37 +01:00
Makefile exec: introduce struct task_exec_state 2026-05-26 11:02:01 +02:00
module_signature.c module: Give 'enum pkey_id_type' a more specific name 2026-03-24 21:42:37 +00:00
notifier.c
nscommon.c nsfs: tighten permission checks for ns iteration ioctls 2026-02-27 22:00:08 +01:00
nsproxy.c vfs-7.1-rc1.mount.v2 2026-04-14 19:59:25 -07:00
nstree.c nstree: tighten permission checks for listing 2026-02-27 22:00:11 +01:00
padata.c padata: Put CPU offline callback in ONLINE section to allow failure 2026-03-22 11:17:59 +09:00
panic.c bug/kunit: Core support for suppressing warning backtraces 2026-05-14 10:50:00 -06:00
params.c kernel: param: initialize module_kset in a pure_initcall 2026-06-08 23:27:56 +02:00
pid_namespace.c pid_namespace: allow opening pid_for_children before init was created 2026-03-20 14:44:26 +01:00
pid_sysctl.h treewide: const qualify ctl_tables where applicable 2025-01-28 13:48:37 +01:00
pid.c pidfd: refuse access to tasks that have started exiting harder 2026-05-19 08:57:47 +02:00
profile.c
ptrace.c exec_state: relocate dumpable information 2026-05-26 11:02:01 +02:00
range.c
reboot.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
regset.c
relay.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
resource_kunit.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
resource.c resource: Make resource_alignment() input const resource 2026-06-23 12:08:51 -05:00
rseq.c rseq: Reenable performance optimizations conditionally 2026-05-06 17:40:27 +02:00
scftorture.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
scs.c scs: fix a wrong parameter in __scs_magic 2025-11-12 10:00:13 -08:00
seccomp.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
signal.c signal: clear JOBCTL_PENDING_MASK for caller in zap_other_threads() 2026-05-22 15:19:31 +02:00
smp.c tracing updates for v7.1: 2026-04-17 09:43:12 -07:00
smpboot.c sched/smp: Use the SMP version of idle_thread_set_boot_cpu() 2025-06-13 08:47:20 +02:00
smpboot.h
softirq.c softirq: Prepare for deferred hrtimer rearming 2026-02-27 16:40:13 +01:00
stacktrace.c
static_call_inline.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
static_call.c
stop_machine.c sched: Simplify ifdeffery around cpu_smt_mask 2026-05-19 12:17:37 +02:00
sys_ni.c rseq: Implement sys_rseq_slice_yield() 2026-01-22 11:11:17 +01:00
sys.c exec_state: relocate dumpable information 2026-05-26 11:02:01 +02:00
sysctl-test.c sysctl: move u8 register test to lib/test_sysctl.c 2025-04-14 14:13:41 +02:00
sysctl.c sysctl: fix uninitialized variable in proc_do_large_bitmap 2026-03-26 09:32:19 +01:00
task_work.c task_work: Fix NMI race condition 2025-10-29 10:29:54 +01:00
taskstats.c taskstats: retain dead thread stats in TGID queries 2026-05-28 21:24:41 -07:00
torture.c torture: Add torture_sched_set_normal() for user-specified nice values 2026-05-24 09:38:47 +02:00
tracepoint.c tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func() 2026-04-14 05:17:02 -04:00
tsacct.c tsacct: skip all kernel threads 2026-01-26 19:07:13 -08:00
ucount.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
uid16.c
uid16.h
umh.c umh: replace use of system_unbound_wq with system_dfl_wq 2026-05-07 11:30:08 -10:00
up.c
user_namespace.c Convert remaining multi-line kmalloc_obj/flex GFP_KERNEL uses 2026-02-22 08:26:33 -08:00
user-return-notifier.c
user.c ns: drop custom reference count initialization for initial namespaces 2025-11-11 10:01:32 +01:00
utsname_sysctl.c treewide: const qualify ctl_tables where applicable 2025-01-28 13:48:37 +01:00
utsname.c namespace-6.18-rc1 2025-09-29 11:20:29 -07:00
vhost_task.c vhost_task_create: kill unnecessary .exit_signal initialization 2026-06-10 02:17:00 -04:00
vmcore_info.c mm.git review status for linus..mm-nonmm-stable 2026-04-16 20:11:56 -07:00
watch_queue.c Convert 'alloc_flex' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
watchdog_buddy.c watchdog/hardlockup: improve buddy system detection timeliness 2026-03-27 21:19:47 -07:00
watchdog_perf.c watchdog/hardlockup: simplify perf event probe and remove per-cpu dependency 2026-02-08 00:13:35 -08:00
watchdog.c watchdog/hardlockup: improve buddy system detection timeliness 2026-03-27 21:19:47 -07:00
workqueue_internal.h workqueue: Show in-flight work item duration in stall diagnostics 2026-03-05 07:27:48 -10:00
workqueue.c workqueue: Changes for v7.2 2026-06-17 11:57:44 +01:00