Skip to content

Commit 9a11b49

Browse files
Ingo MolnarLinus Torvalds
authored andcommitted
[PATCH] lockdep: better lock debugging
Generic lock debugging: - generalized lock debugging framework. For example, a bug in one lock subsystem turns off debugging in all lock subsystems. - got rid of the caller address passing (__IP__/__IP_DECL__/etc.) from the mutex/rtmutex debugging code: it caused way too much prototype hackery, and lockdep will give the same information anyway. - ability to do silent tests - check lock freeing in vfree too. - more finegrained debugging options, to allow distributions to turn off more expensive debugging features. There's no separate 'held mutexes' list anymore - but there's a 'held locks' stack within lockdep, which unifies deadlock detection across all lock classes. (this is independent of the lockdep validation stuff - lockdep first checks whether we are holding a lock already) Here are the current debugging options: CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_LOCK_ALLOC=y which do: config DEBUG_MUTEXES bool "Mutex debugging, basic checks" config DEBUG_LOCK_ALLOC bool "Detect incorrect freeing of live mutexes" Signed-off-by: Ingo Molnar <[email protected]> Signed-off-by: Arjan van de Ven <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fb7e424 commit 9a11b49

File tree

25 files changed

+265
-567
lines changed

25 files changed

+265
-567
lines changed

drivers/char/sysrq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ static struct sysrq_key_op sysrq_mountro_op = {
151151
static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs,
152152
struct tty_struct *tty)
153153
{
154-
mutex_debug_show_all_locks();
154+
debug_show_all_locks();
155155
}
156156
static struct sysrq_key_op sysrq_showlocks_op = {
157157
.handler = sysrq_handle_showlocks,

include/asm-generic/mutex-null.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,10 @@
1010
#ifndef _ASM_GENERIC_MUTEX_NULL_H
1111
#define _ASM_GENERIC_MUTEX_NULL_H
1212

13-
/* extra parameter only needed for mutex debugging: */
14-
#ifndef __IP__
15-
# define __IP__
16-
#endif
17-
18-
#define __mutex_fastpath_lock(count, fail_fn) fail_fn(count __RET_IP__)
19-
#define __mutex_fastpath_lock_retval(count, fail_fn) fail_fn(count __RET_IP__)
20-
#define __mutex_fastpath_unlock(count, fail_fn) fail_fn(count __RET_IP__)
21-
#define __mutex_fastpath_trylock(count, fail_fn) fail_fn(count)
22-
#define __mutex_slowpath_needs_to_unlock() 1
13+
#define __mutex_fastpath_lock(count, fail_fn) fail_fn(count)
14+
#define __mutex_fastpath_lock_retval(count, fail_fn) fail_fn(count)
15+
#define __mutex_fastpath_unlock(count, fail_fn) fail_fn(count)
16+
#define __mutex_fastpath_trylock(count, fail_fn) fail_fn(count)
17+
#define __mutex_slowpath_needs_to_unlock() 1
2318

2419
#endif

include/linux/debug_locks.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#ifndef __LINUX_DEBUG_LOCKING_H
2+
#define __LINUX_DEBUG_LOCKING_H
3+
4+
extern int debug_locks;
5+
extern int debug_locks_silent;
6+
7+
/*
8+
* Generic 'turn off all lock debugging' function:
9+
*/
10+
extern int debug_locks_off(void);
11+
12+
/*
13+
* In the debug case we carry the caller's instruction pointer into
14+
* other functions, but we dont want the function argument overhead
15+
* in the nondebug case - hence these macros:
16+
*/
17+
#define _RET_IP_ (unsigned long)__builtin_return_address(0)
18+
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
19+
20+
#define DEBUG_LOCKS_WARN_ON(c) \
21+
({ \
22+
int __ret = 0; \
23+
\
24+
if (unlikely(c)) { \
25+
if (debug_locks_off()) \
26+
WARN_ON(1); \
27+
__ret = 1; \
28+
} \
29+
__ret; \
30+
})
31+
32+
#ifdef CONFIG_SMP
33+
# define SMP_DEBUG_LOCKS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c)
34+
#else
35+
# define SMP_DEBUG_LOCKS_WARN_ON(c) do { } while (0)
36+
#endif
37+
38+
#ifdef CONFIG_DEBUG_LOCKING_API_SELFTESTS
39+
extern void locking_selftest(void);
40+
#else
41+
# define locking_selftest() do { } while (0)
42+
#endif
43+
44+
#ifdef CONFIG_LOCKDEP
45+
extern void debug_show_all_locks(void);
46+
extern void debug_show_held_locks(struct task_struct *task);
47+
extern void debug_check_no_locks_freed(const void *from, unsigned long len);
48+
extern void debug_check_no_locks_held(struct task_struct *task);
49+
#else
50+
static inline void debug_show_all_locks(void)
51+
{
52+
}
53+
54+
static inline void debug_show_held_locks(struct task_struct *task)
55+
{
56+
}
57+
58+
static inline void
59+
debug_check_no_locks_freed(const void *from, unsigned long len)
60+
{
61+
}
62+
63+
static inline void
64+
debug_check_no_locks_held(struct task_struct *task)
65+
{
66+
}
67+
#endif
68+
69+
#endif

include/linux/init_task.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ extern struct group_info init_groups;
124124
.cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
125125
.fs_excl = ATOMIC_INIT(0), \
126126
.pi_lock = SPIN_LOCK_UNLOCKED, \
127-
INIT_RT_MUTEXES(tsk) \
128127
}
129128

130129

include/linux/mm.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/prio_tree.h>
1515
#include <linux/fs.h>
1616
#include <linux/mutex.h>
17+
#include <linux/debug_locks.h>
1718

1819
struct mempolicy;
1920
struct anon_vma;
@@ -1034,13 +1035,6 @@ static inline void vm_stat_account(struct mm_struct *mm,
10341035
}
10351036
#endif /* CONFIG_PROC_FS */
10361037

1037-
static inline void
1038-
debug_check_no_locks_freed(const void *from, unsigned long len)
1039-
{
1040-
mutex_debug_check_no_locks_freed(from, len);
1041-
rt_mutex_debug_check_no_locks_freed(from, len);
1042-
}
1043-
10441038
#ifndef CONFIG_DEBUG_PAGEALLOC
10451039
static inline void
10461040
kernel_map_pages(struct page *page, int numpages, int enable)

include/linux/mutex-debug.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,11 @@
77
* Mutexes - debugging helpers:
88
*/
99

10-
#define __DEBUG_MUTEX_INITIALIZER(lockname) \
11-
, .held_list = LIST_HEAD_INIT(lockname.held_list), \
12-
.name = #lockname , .magic = &lockname
10+
#define __DEBUG_MUTEX_INITIALIZER(lockname) \
11+
, .magic = &lockname
1312

14-
#define mutex_init(sem) __mutex_init(sem, __FUNCTION__)
13+
#define mutex_init(sem) __mutex_init(sem, __FILE__":"#sem)
1514

1615
extern void FASTCALL(mutex_destroy(struct mutex *lock));
1716

18-
extern void mutex_debug_show_all_locks(void);
19-
extern void mutex_debug_show_held_locks(struct task_struct *filter);
20-
extern void mutex_debug_check_no_locks_held(struct task_struct *task);
21-
extern void mutex_debug_check_no_locks_freed(const void *from, unsigned long len);
22-
2317
#endif

include/linux/mutex.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ struct mutex {
5050
struct list_head wait_list;
5151
#ifdef CONFIG_DEBUG_MUTEXES
5252
struct thread_info *owner;
53-
struct list_head held_list;
54-
unsigned long acquire_ip;
5553
const char *name;
5654
void *magic;
5755
#endif
@@ -76,10 +74,6 @@ struct mutex_waiter {
7674
# define __DEBUG_MUTEX_INITIALIZER(lockname)
7775
# define mutex_init(mutex) __mutex_init(mutex, NULL)
7876
# define mutex_destroy(mutex) do { } while (0)
79-
# define mutex_debug_show_all_locks() do { } while (0)
80-
# define mutex_debug_show_held_locks(p) do { } while (0)
81-
# define mutex_debug_check_no_locks_held(task) do { } while (0)
82-
# define mutex_debug_check_no_locks_freed(from, len) do { } while (0)
8377
#endif
8478

8579
#define __MUTEX_INITIALIZER(lockname) \

include/linux/rtmutex.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ struct rt_mutex {
2929
struct task_struct *owner;
3030
#ifdef CONFIG_DEBUG_RT_MUTEXES
3131
int save_state;
32-
struct list_head held_list_entry;
33-
unsigned long acquire_ip;
3432
const char *name, *file;
3533
int line;
3634
void *magic;
@@ -98,14 +96,6 @@ extern int rt_mutex_trylock(struct rt_mutex *lock);
9896

9997
extern void rt_mutex_unlock(struct rt_mutex *lock);
10098

101-
#ifdef CONFIG_DEBUG_RT_MUTEXES
102-
# define INIT_RT_MUTEX_DEBUG(tsk) \
103-
.held_list_head = LIST_HEAD_INIT(tsk.held_list_head), \
104-
.held_list_lock = SPIN_LOCK_UNLOCKED
105-
#else
106-
# define INIT_RT_MUTEX_DEBUG(tsk)
107-
#endif
108-
10999
#ifdef CONFIG_RT_MUTEXES
110100
# define INIT_RT_MUTEXES(tsk) \
111101
.pi_waiters = PLIST_HEAD_INIT(tsk.pi_waiters, tsk.pi_lock), \

include/linux/sched.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -865,10 +865,6 @@ struct task_struct {
865865
struct plist_head pi_waiters;
866866
/* Deadlock detection and priority inheritance handling */
867867
struct rt_mutex_waiter *pi_blocked_on;
868-
# ifdef CONFIG_DEBUG_RT_MUTEXES
869-
spinlock_t held_list_lock;
870-
struct list_head held_list_head;
871-
# endif
872868
#endif
873869

874870
#ifdef CONFIG_DEBUG_MUTEXES

init/main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <linux/key.h>
4848
#include <linux/unwind.h>
4949
#include <linux/buffer_head.h>
50+
#include <linux/debug_locks.h>
5051

5152
#include <asm/io.h>
5253
#include <asm/bugs.h>
@@ -511,6 +512,13 @@ asmlinkage void __init start_kernel(void)
511512
console_init();
512513
if (panic_later)
513514
panic(panic_later, panic_param);
515+
/*
516+
* Need to run this when irqs are enabled, because it wants
517+
* to self-test [hard/soft]-irqs on/off lock inversion bugs
518+
* too:
519+
*/
520+
locking_selftest();
521+
514522
#ifdef CONFIG_BLK_DEV_INITRD
515523
if (initrd_start && !initrd_below_start_ok &&
516524
initrd_start < min_low_pfn << PAGE_SHIFT) {

0 commit comments

Comments
 (0)