On this page
Synchronization Debugging
Coverage: lockdep (lock dependency graph) → lockstat (contention statistics) → KCSAN (data race detection) → hung task detector → NMI watchdog → CONFIG_DEBUG_ATOMIC_SLEEP Kernel versions: 2.6 ~ 6.x
Overview
Concurrency bugs are among the most difficult issues to debug in the kernel: deadlocks, data races, and sleeping in atomic context. These bugs are often non-deterministic—triggering only under specific timing conditions. Fortunately, the kernel includes a powerful synchronization debugging infrastructure that can catch them when they occur (or even before they happen).
Lockdep: Lock Dependency Validator
// kernel/locking/lockdep.c
// Core idea: Build a runtime lock dependency graph and check for cycles (deadlocks)
// On each lock: add an edge A→B in the graph
// If an edge B→A already exists → emit a deadlock warning!
//
// A deadlock doesn't need to actually occur! Lockdep can "predict" potential deadlocks
// "Lock classes" tracked by Lockdep:
// - Locks of the same type (e.g., all inode→i_lock) → same class
// - Locks taken in different functions → different classes (even if the type is the same)
// /proc/lockdep: complete lock dependency graph
// /proc/lockdep_stats: dependency graph statistics
Interpreting Lockdep Reports
Typical lockdep output:
======================================================
WARNING: possible circular locking dependency detected
======================================================
CPU 0: lock(A); ... lock(B);
CPU 1: lock(B); ... lock(A);
→ Potential deadlock! Even if it hasn't occurred in actual execution yet
// Also includes:
// - Which function and file acquired each lock
// - Hold history for each lock since boot
Lockstat: Contention Statistics
// CONFIG_LOCK_STAT
// Records per-lock:
// - wait time: how long it waited for the lock
// - hold time: how long the lock was held (requires CONFIG_LOCK_STAT_HOLDLOCK)
// /proc/lock_stat:
// Format: class_name contended total_wait_ns max_wait_ns min_wait_ns
KCSAN: Kernel Concurrency Sanitizer
// kernel/kcsan/
// Similar to user-space ThreadSanitizer (TSan)
// Detects data races at runtime: two CPUs accessing the same memory address simultaneously, with at least one being a write
// How it works:
// 1. For every memory access: record address + size + timestamp (watchpoint)
// 2. If another CPU accesses the same address without synchronization → report it
// Interpreting reports:
// BUG: KCSAN: data-race in function_name (read/write of 4 bytes at addr)
// CPU 0: write to x in func_a()
// CPU 1: read from x in func_b()
// → Access to x is not protected by a common lock → data race!
// Compile option: CONFIG_KCSAN=y
// Kernels built with KCSAN are significantly slower (~10x), intended for debugging only
Hung Task Detector
Detection: Processes in TASK_UNINTERRUPTIBLE (D) state for more than 120 seconds
→ Usually caused by deadlocks, unreachable NFS, or driver bugs
Configuration:
/proc/sys/kernel/hung_task_timeout_secs (default 120)
/proc/sys/kernel/hung_task_panic (0=warn, 1=panic)
Output: Prints the kernel stack of the hung process (critical!)
→ If you see it waiting in mutex_lock() → find which process holds that lock
NMI Watchdog
Deadlock detection based on NMI (Non-Maskable Interrupt):
Each CPU periodically receives NMIs → resetting per-CPU counters
If a CPU hasn't received an NMI for a long time:
→ Likely due to disabling interrupts for too long (spin_lock_irqsave infinite loop)
→ Prints the stack backtrace of the hung CPU
How it works:
perf event driver → overflow → NMI → watchdog overflow handler
→ Checks hrtimer time since last interrupt → if timeout → alarm
Other Debugging Tools
// CONFIG_DEBUG_ATOMIC_SLEEP:
// Calling schedule() (or any function that might sleep) in an atomic context
// → Immediately BUG()
// CONFIG_PROVE_LOCKING (enhancement for lockdep):
// Every lock operation is checked by lockdep → higher runtime overhead
// But it catches more incorrect lock usage
// CONFIG_DEBUG_SPINLOCK:
// Checks for uninitialized spinlock usage, double unlock, etc.
// CONFIG_PROVE_RCU:
// Checks for RCU readers calling rcu_dereference or sleeping outside critical sections
Quick Reference for Debugging Commands
# lockdep: dependency graph + statistics
# lockstat: contention
| |
# hung task: currently hung processes
# Data races (KCSAN, requires compile-time enablement)
|
# Interrupt-disabled checks
|
References
- Kernel Documentation:
Documentation/locking/lockdep-design.rst,Documentation/dev-tools/kcsan.rst - Source Code:
kernel/locking/lockdep.c,kernel/kcsan/,kernel/watchdog.c,kernel/hung_task.c - LWN: "Lockdep", "The Kernel Concurrency Sanitizer"
Keywords: lockdep, lockstat, KCSAN, data race, hung task, NMI watchdog, DEBUG_ATOMIC_SLEEP, PROVE_LOCKING