[PATCH bpf-next v2 14/26] rqspinlock: Add helper to print a splat on timeout or deadlock

Kumar Kartikeya Dwivedi
2025-02-06T10:54:58Z

Whenever a timeout and a deadlock occurs, we would want to print a
message to the dmesg console, including the CPU where the event
occurred, the list of locks in the held locks table, and the stack trace
of the caller, which allows determining where exactly in the slow path
the waiter timed out or detected a deadlock.

Splats are limited to atmost one per-CPU during machine uptime, and a
lock is acquired to ensure that no interleaving occurs when a concurrent
set of CPUs conflict and enter a deadlock situation and start printing
data.

Later patches will use this to inspect return value of rqspinlock API
and then report a violation if necessary.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/locking/rqspinlock.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/kernel/locking/rqspinlock.c b/kernel/locking/rqspinlock.c
index 13d1759c9353..93f928bc4e9c 100644
--- a/kernel/locking/rqspinlock.c
+++ b/kernel/locking/rqspinlock.c
@@ -196,6 +196,35 @@ static noinline int check_deadlock_ABBA(rqspinlock_t *lock, u32 mask,
return 0;
}

+static DEFINE_PER_CPU(int, report_nest_cnt);
+static DEFINE_PER_CPU(bool, report_flag);
+static arch_spinlock_t report_lock;
+
+static void rqspinlock_report_violation(const char *s, void *lock)
+{
+ struct rqspinlock_held *rqh = this_cpu_ptr(&rqspinlock_held_locks);
+
+ if (this_cpu_inc_return(report_nest_cnt) != 1) {
+ this_cpu_dec(report_nest_cnt);
+ return;
+ }
+ if (this_cpu_read(report_flag))
+ goto end;
+ this_cpu_write(report_flag, true);
+ arch_spin_lock(&report_lock);
+
+ pr_err("CPU %d: %s", smp_processor_id(), s);
+ pr_info("Held locks: %d\n", rqh->cnt + 1);
+ pr_info("Held lock[%2d] = 0x%px\n", 0, lock);
+ for (int i = 0; i < min(RES_NR_HELD, rqh->cnt); i++)
+ pr_info("Held lock[%2d] = 0x%px\n", i + 1, rqh->locks[i]);
+ dump_stack();
+
+ arch_spin_unlock(&report_lock);
+end:
+ this_cpu_dec(report_nest_cnt);
+}
+
static noinline int check_deadlock(rqspinlock_t *lock, u32 mask,
struct rqspinlock_timeout *ts)
{
--
2.43.5