Linux-Next discussions
 help / color / mirror / Atom feed
From: Ingo Molnar <mingo@kernel.org>
To: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: Boqun Feng <boqun@kernel.org>, Gary Guo <gary@garyguo.net>,
	Mark Brown <broonie@kernel.org>,
	linux-next@vger.kernel.org, linux-kernel@vger.kernel.org,
	Miguel Ojeda <ojeda@kernel.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	peterz@infradead.org, will@kernel.org, longman@redhat.com,
	gregkh@linuxfoundation.org
Subject: [PATCH] lockdep: Enable the printing of held locks of running non-current tasks  (was: Policy regarding linux-next only changes)
Date: Sun, 5 Jul 2026 11:05:12 +0200	[thread overview]
Message-ID: <akoeSIQGwqd9cZwd@gmail.com> (raw)
In-Reply-To: <7f1b93a9-f756-4bfc-81d7-1350ac1d50ac@I-love.SAKURA.ne.jp>


* Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote:

> On 2026/07/02 23:11, Boqun Feng wrote:
> >>> While testing lockdep changes on linux-next, I found there is a commit
> >>> ca65ccfdc5b3 ("locking/lockdep: make lockdep_print_held_locks() always print if
> >>> CONFIG_DEBUG_AID_FOR_SYZBOT=y") applied to lockdep. Checking the history it
> >>> looks like this commit has been in linux-next for quite a while (at least 2
> >>> months); there were no emails on LKML about this commit at all.

Yeah, 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 a warning when we print
such a task, so that users are aware of any racy output.

The (lightly tested) patch below implements this.

Note that this way there's no need to gate this on the Syzkaller
config option, and you wouldn't have to carry it in -next either,
it's a useful mainline kernel debuggability enhancement in its
own right.

Would this work for you?

Thanks,

	Ingo

=================>
From: Ingo Molnar <mingo@kernel.org>
Date: Sun, 5 Jul 2026 10:38:06 +0200
Subject: [PATCH] lockdep: Enable the printing of held locks of running non-current tasks

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 a warning when we print
such a task, so that users are aware of any racy output.

This commit implements that change.

For running tasks, the printout adds a warning about the
fact that the task is running and that the held locks array
is in flux:

  5 locks held by bash/1234 (WARNING: task running):
  ...

Note that while re-flowing the function this change also
micro-optimizes the common !depth case, which unnecessarily
ran through the runnability check and the (zero-steps) loop.

Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 kernel/locking/lockdep.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 2d4c5bab5af8..4b193bdc8552 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -786,18 +786,23 @@ static void print_lock(struct held_lock *hlock)
 static void lockdep_print_held_locks(struct task_struct *p)
 {
 	int i, depth = READ_ONCE(p->lockdep_depth);
+	const char *msg_running = "";
 
-	if (!depth)
+	if (!depth) {
 		printk("no locks held by %s/%d.\n", p->comm, task_pid_nr(p));
-	else
-		printk("%d lock%s held by %s/%d:\n", depth,
-		       str_plural(depth), p->comm, task_pid_nr(p));
+		return;
+	}
+
 	/*
-	 * It's not reliable to print a task's held locks if it's not sleeping
-	 * and it's not the current task.
+	 * It's not reliable to print a task's held locks if it's not
+	 * sleeping and it's not the current task:
 	 */
 	if (p != current && task_is_running(p))
-		return;
+		msg_running = " (WARNING: task running)";
+
+	printk("%d lock%s held by %s/%d%s:\n", depth,
+	       str_plural(depth), p->comm, task_pid_nr(p), msg_running);
+
 	for (i = 0; i < depth; i++) {
 		printk(" #%d: ", i);
 		print_lock(p->held_locks + i);

  parent reply	other threads:[~2026-07-05  9:05 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-02 11:49 Policy regarding linux-next only changes Gary Guo
2026-07-02 12:49 ` Tetsuo Handa
2026-07-02 13:37   ` Miguel Ojeda
2026-07-02 14:11   ` Boqun Feng
2026-07-04 10:14     ` Tetsuo Handa
2026-07-04 12:06       ` Miguel Ojeda
2026-07-04 13:22         ` Theodore Tso
2026-07-05 11:36           ` Tetsuo Handa
2026-07-05 12:02             ` Miguel Ojeda
2026-07-05 12:06               ` Miguel Ojeda
2026-07-05 12:20               ` Mark Brown
2026-07-05 12:06         ` Mark Brown
2026-07-05 14:16           ` Tetsuo Handa
2026-07-06 17:23             ` Mark Brown
2026-07-05  9:05       ` Ingo Molnar [this message]
2026-07-05 11:05         ` [PATCH] lockdep: Enable the printing of held locks of running non-current tasks Tetsuo Handa
2026-07-07  7:20           ` [PATCH -v2] lockdep: Enable the printing of held locks of remote running tasks and print task CPU Ingo Molnar
2026-07-05 14:59       ` Policy regarding linux-next only changes Boqun Feng
2026-07-02 13:22 ` Mark Brown

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=akoeSIQGwqd9cZwd@gmail.com \
    --to=mingo@kernel.org \
    --cc=boqun@kernel.org \
    --cc=broonie@kernel.org \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-next@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=penguin-kernel@i-love.sakura.ne.jp \
    --cc=peterz@infradead.org \
    --cc=torvalds@linux-foundation.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