Loading Documentation/lockdep-design.txt +17 −13 Original line number Diff line number Diff line Loading @@ -27,33 +27,37 @@ lock-class. State ----- The validator tracks lock-class usage history into 5 separate state bits: The validator tracks lock-class usage history into 4n + 1 separate state bits: - 'ever held in hardirq context' [ == hardirq-safe ] - 'ever held in softirq context' [ == softirq-safe ] - 'ever held with hardirqs enabled' [ == hardirq-unsafe ] - 'ever held with softirqs and hardirqs enabled' [ == softirq-unsafe ] - 'ever held in STATE context' - 'ever head as readlock in STATE context' - 'ever head with STATE enabled' - 'ever head as readlock with STATE enabled' Where STATE can be either one of (kernel/lockdep_states.h) - hardirq - softirq - reclaim_fs - 'ever used' [ == !unused ] When locking rules are violated, these 4 state bits are presented in the When locking rules are violated, these state bits are presented in the locking error messages, inside curlies. A contrived example: modprobe/2287 is trying to acquire lock: (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24 but task is already holding lock: (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24 The bit position indicates hardirq, softirq, hardirq-read, softirq-read respectively, and the character displayed in each indicates: The bit position indicates STATE, STATE-read, for each of the states listed above, and the character displayed in each indicates: '.' acquired while irqs disabled '+' acquired in irq context '-' acquired with irqs enabled '?' read acquired in irq context with irqs enabled. '?' acquired in irq context with irqs enabled. Unused mutexes cannot be part of the cause of an error. Loading include/linux/lockdep.h +12 −38 Original line number Diff line number Diff line Loading @@ -20,43 +20,10 @@ struct lockdep_map; #include <linux/stacktrace.h> /* * Lock-class usage-state bits: * We'd rather not expose kernel/lockdep_states.h this wide, but we do need * the total number of states... :-( */ enum lock_usage_bit { LOCK_USED = 0, LOCK_USED_IN_HARDIRQ, LOCK_USED_IN_SOFTIRQ, LOCK_ENABLED_SOFTIRQS, LOCK_ENABLED_HARDIRQS, LOCK_USED_IN_HARDIRQ_READ, LOCK_USED_IN_SOFTIRQ_READ, LOCK_ENABLED_SOFTIRQS_READ, LOCK_ENABLED_HARDIRQS_READ, LOCK_USAGE_STATES }; /* * Usage-state bitmasks: */ #define LOCKF_USED (1 << LOCK_USED) #define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) #define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) #define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) #define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) #define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) #define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) #define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) #define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) #define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) #define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) #define LOCKF_ENABLED_IRQS_READ \ (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) #define LOCKF_USED_IN_IRQ_READ \ (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) #define XXX_LOCK_USAGE_STATES (1+3*4) #define MAX_LOCKDEP_SUBCLASSES 8UL Loading Loading @@ -97,7 +64,7 @@ struct lock_class { * IRQ/softirq usage tracking bits: */ unsigned long usage_mask; struct stack_trace usage_traces[LOCK_USAGE_STATES]; struct stack_trace usage_traces[XXX_LOCK_USAGE_STATES]; /* * These fields represent a directed graph of lock dependencies, Loading Loading @@ -324,7 +291,11 @@ static inline void lock_set_subclass(struct lockdep_map *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } # define INIT_LOCKDEP .lockdep_recursion = 0, extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); # define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) Loading @@ -342,6 +313,9 @@ static inline void lockdep_on(void) # define lock_release(l, n, i) do { } while (0) # define lock_set_class(l, n, k, s, i) do { } while (0) # define lock_set_subclass(l, s, i) do { } while (0) # define lockdep_set_current_reclaim_state(g) do { } while (0) # define lockdep_clear_current_reclaim_state() do { } while (0) # define lockdep_trace_alloc(g) do { } while (0) # define lockdep_init() do { } while (0) # define lockdep_info() do { } while (0) # define lockdep_init_map(lock, name, key, sub) \ Loading include/linux/mutex.h +3 −2 Original line number Diff line number Diff line Loading @@ -50,8 +50,10 @@ struct mutex { atomic_t count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_MUTEXES #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) struct thread_info *owner; #endif #ifdef CONFIG_DEBUG_MUTEXES const char *name; void *magic; #endif Loading @@ -68,7 +70,6 @@ struct mutex_waiter { struct list_head list; struct task_struct *task; #ifdef CONFIG_DEBUG_MUTEXES struct mutex *lock; void *magic; #endif }; Loading include/linux/ring_buffer.h +5 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,9 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); u64 ring_buffer_time_stamp(int cpu); void ring_buffer_normalize_time_stamp(int cpu, u64 *ts); size_t ring_buffer_page_len(void *page); /* * The below functions are fine to use outside the tracing facility. */ Loading @@ -138,8 +141,8 @@ static inline int tracing_is_on(void) { return 0; } void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, int cpu, int full); int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, size_t len, int cpu, int full); enum ring_buffer_flags { RB_FL_OVERWRITE = 1 << 0, Loading include/linux/sched.h +3 −0 Original line number Diff line number Diff line Loading @@ -333,7 +333,9 @@ extern signed long schedule_timeout(signed long timeout); extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_killable(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void __schedule(void); asmlinkage void schedule(void); extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner); struct nsproxy; struct user_namespace; Loading Loading @@ -1330,6 +1332,7 @@ struct task_struct { int lockdep_depth; unsigned int lockdep_recursion; struct held_lock held_locks[MAX_LOCK_DEPTH]; gfp_t lockdep_reclaim_gfp; #endif /* journalling filesystem info */ Loading Loading
Documentation/lockdep-design.txt +17 −13 Original line number Diff line number Diff line Loading @@ -27,33 +27,37 @@ lock-class. State ----- The validator tracks lock-class usage history into 5 separate state bits: The validator tracks lock-class usage history into 4n + 1 separate state bits: - 'ever held in hardirq context' [ == hardirq-safe ] - 'ever held in softirq context' [ == softirq-safe ] - 'ever held with hardirqs enabled' [ == hardirq-unsafe ] - 'ever held with softirqs and hardirqs enabled' [ == softirq-unsafe ] - 'ever held in STATE context' - 'ever head as readlock in STATE context' - 'ever head with STATE enabled' - 'ever head as readlock with STATE enabled' Where STATE can be either one of (kernel/lockdep_states.h) - hardirq - softirq - reclaim_fs - 'ever used' [ == !unused ] When locking rules are violated, these 4 state bits are presented in the When locking rules are violated, these state bits are presented in the locking error messages, inside curlies. A contrived example: modprobe/2287 is trying to acquire lock: (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24 but task is already holding lock: (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24 (&sio_locks[i].lock){-.-...}, at: [<c02867fd>] mutex_lock+0x21/0x24 The bit position indicates hardirq, softirq, hardirq-read, softirq-read respectively, and the character displayed in each indicates: The bit position indicates STATE, STATE-read, for each of the states listed above, and the character displayed in each indicates: '.' acquired while irqs disabled '+' acquired in irq context '-' acquired with irqs enabled '?' read acquired in irq context with irqs enabled. '?' acquired in irq context with irqs enabled. Unused mutexes cannot be part of the cause of an error. Loading
include/linux/lockdep.h +12 −38 Original line number Diff line number Diff line Loading @@ -20,43 +20,10 @@ struct lockdep_map; #include <linux/stacktrace.h> /* * Lock-class usage-state bits: * We'd rather not expose kernel/lockdep_states.h this wide, but we do need * the total number of states... :-( */ enum lock_usage_bit { LOCK_USED = 0, LOCK_USED_IN_HARDIRQ, LOCK_USED_IN_SOFTIRQ, LOCK_ENABLED_SOFTIRQS, LOCK_ENABLED_HARDIRQS, LOCK_USED_IN_HARDIRQ_READ, LOCK_USED_IN_SOFTIRQ_READ, LOCK_ENABLED_SOFTIRQS_READ, LOCK_ENABLED_HARDIRQS_READ, LOCK_USAGE_STATES }; /* * Usage-state bitmasks: */ #define LOCKF_USED (1 << LOCK_USED) #define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) #define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) #define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) #define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) #define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) #define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) #define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) #define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) #define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) #define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) #define LOCKF_ENABLED_IRQS_READ \ (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) #define LOCKF_USED_IN_IRQ_READ \ (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ) #define XXX_LOCK_USAGE_STATES (1+3*4) #define MAX_LOCKDEP_SUBCLASSES 8UL Loading Loading @@ -97,7 +64,7 @@ struct lock_class { * IRQ/softirq usage tracking bits: */ unsigned long usage_mask; struct stack_trace usage_traces[LOCK_USAGE_STATES]; struct stack_trace usage_traces[XXX_LOCK_USAGE_STATES]; /* * These fields represent a directed graph of lock dependencies, Loading Loading @@ -324,7 +291,11 @@ static inline void lock_set_subclass(struct lockdep_map *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } # define INIT_LOCKDEP .lockdep_recursion = 0, extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); # define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) Loading @@ -342,6 +313,9 @@ static inline void lockdep_on(void) # define lock_release(l, n, i) do { } while (0) # define lock_set_class(l, n, k, s, i) do { } while (0) # define lock_set_subclass(l, s, i) do { } while (0) # define lockdep_set_current_reclaim_state(g) do { } while (0) # define lockdep_clear_current_reclaim_state() do { } while (0) # define lockdep_trace_alloc(g) do { } while (0) # define lockdep_init() do { } while (0) # define lockdep_info() do { } while (0) # define lockdep_init_map(lock, name, key, sub) \ Loading
include/linux/mutex.h +3 −2 Original line number Diff line number Diff line Loading @@ -50,8 +50,10 @@ struct mutex { atomic_t count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_MUTEXES #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) struct thread_info *owner; #endif #ifdef CONFIG_DEBUG_MUTEXES const char *name; void *magic; #endif Loading @@ -68,7 +70,6 @@ struct mutex_waiter { struct list_head list; struct task_struct *task; #ifdef CONFIG_DEBUG_MUTEXES struct mutex *lock; void *magic; #endif }; Loading
include/linux/ring_buffer.h +5 −2 Original line number Diff line number Diff line Loading @@ -121,6 +121,9 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); u64 ring_buffer_time_stamp(int cpu); void ring_buffer_normalize_time_stamp(int cpu, u64 *ts); size_t ring_buffer_page_len(void *page); /* * The below functions are fine to use outside the tracing facility. */ Loading @@ -138,8 +141,8 @@ static inline int tracing_is_on(void) { return 0; } void *ring_buffer_alloc_read_page(struct ring_buffer *buffer); void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, int cpu, int full); int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, size_t len, int cpu, int full); enum ring_buffer_flags { RB_FL_OVERWRITE = 1 << 0, Loading
include/linux/sched.h +3 −0 Original line number Diff line number Diff line Loading @@ -333,7 +333,9 @@ extern signed long schedule_timeout(signed long timeout); extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_killable(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void __schedule(void); asmlinkage void schedule(void); extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner); struct nsproxy; struct user_namespace; Loading Loading @@ -1330,6 +1332,7 @@ struct task_struct { int lockdep_depth; unsigned int lockdep_recursion; struct held_lock held_locks[MAX_LOCK_DEPTH]; gfp_t lockdep_reclaim_gfp; #endif /* journalling filesystem info */ Loading