diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-07-03 03:24:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 18:27:01 -0400 |
commit | 9a11b49a805665e13a56aa067afaf81d43ec1514 (patch) | |
tree | bf499956e3f67d1211d68ab1e2eb76645f453dfb /kernel/mutex-debug.h | |
parent | fb7e42413a098cc45b3adf858da290033af62bae (diff) |
[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 <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/mutex-debug.h')
-rw-r--r-- | kernel/mutex-debug.h | 82 |
1 files changed, 12 insertions, 70 deletions
diff --git a/kernel/mutex-debug.h b/kernel/mutex-debug.h index bdab13a9ee26..babfbdfc534b 100644 --- a/kernel/mutex-debug.h +++ b/kernel/mutex-debug.h | |||
@@ -10,102 +10,44 @@ | |||
10 | * More details are in kernel/mutex-debug.c. | 10 | * More details are in kernel/mutex-debug.c. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | extern spinlock_t debug_mutex_lock; | ||
14 | extern struct list_head debug_mutex_held_locks; | ||
15 | extern int debug_mutex_on; | ||
16 | |||
17 | /* | ||
18 | * In the debug case we carry the caller's instruction pointer into | ||
19 | * other functions, but we dont want the function argument overhead | ||
20 | * in the nondebug case - hence these macros: | ||
21 | */ | ||
22 | #define __IP_DECL__ , unsigned long ip | ||
23 | #define __IP__ , ip | ||
24 | #define __RET_IP__ , (unsigned long)__builtin_return_address(0) | ||
25 | |||
26 | /* | 13 | /* |
27 | * This must be called with lock->wait_lock held. | 14 | * This must be called with lock->wait_lock held. |
28 | */ | 15 | */ |
29 | extern void debug_mutex_set_owner(struct mutex *lock, | 16 | extern void |
30 | struct thread_info *new_owner __IP_DECL__); | 17 | debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner); |
31 | 18 | ||
32 | static inline void debug_mutex_clear_owner(struct mutex *lock) | 19 | static inline void debug_mutex_clear_owner(struct mutex *lock) |
33 | { | 20 | { |
34 | lock->owner = NULL; | 21 | lock->owner = NULL; |
35 | } | 22 | } |
36 | 23 | ||
37 | extern void debug_mutex_init_waiter(struct mutex_waiter *waiter); | 24 | extern void debug_mutex_lock_common(struct mutex *lock, |
25 | struct mutex_waiter *waiter); | ||
38 | extern void debug_mutex_wake_waiter(struct mutex *lock, | 26 | extern void debug_mutex_wake_waiter(struct mutex *lock, |
39 | struct mutex_waiter *waiter); | 27 | struct mutex_waiter *waiter); |
40 | extern void debug_mutex_free_waiter(struct mutex_waiter *waiter); | 28 | extern void debug_mutex_free_waiter(struct mutex_waiter *waiter); |
41 | extern void debug_mutex_add_waiter(struct mutex *lock, | 29 | extern void debug_mutex_add_waiter(struct mutex *lock, |
42 | struct mutex_waiter *waiter, | 30 | struct mutex_waiter *waiter, |
43 | struct thread_info *ti __IP_DECL__); | 31 | struct thread_info *ti); |
44 | extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, | 32 | extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, |
45 | struct thread_info *ti); | 33 | struct thread_info *ti); |
46 | extern void debug_mutex_unlock(struct mutex *lock); | 34 | extern void debug_mutex_unlock(struct mutex *lock); |
47 | extern void debug_mutex_init(struct mutex *lock, const char *name); | 35 | extern void debug_mutex_init(struct mutex *lock, const char *name, |
48 | 36 | struct lock_class_key *key); | |
49 | #define debug_spin_lock_save(lock, flags) \ | ||
50 | do { \ | ||
51 | local_irq_save(flags); \ | ||
52 | if (debug_mutex_on) \ | ||
53 | spin_lock(lock); \ | ||
54 | } while (0) | ||
55 | |||
56 | #define debug_spin_unlock_restore(lock, flags) \ | ||
57 | do { \ | ||
58 | if (debug_mutex_on) \ | ||
59 | spin_unlock(lock); \ | ||
60 | local_irq_restore(flags); \ | ||
61 | preempt_check_resched(); \ | ||
62 | } while (0) | ||
63 | 37 | ||
64 | #define spin_lock_mutex(lock, flags) \ | 38 | #define spin_lock_mutex(lock, flags) \ |
65 | do { \ | 39 | do { \ |
66 | struct mutex *l = container_of(lock, struct mutex, wait_lock); \ | 40 | struct mutex *l = container_of(lock, struct mutex, wait_lock); \ |
67 | \ | 41 | \ |
68 | DEBUG_LOCKS_WARN_ON(in_interrupt()); \ | 42 | DEBUG_LOCKS_WARN_ON(in_interrupt()); \ |
69 | debug_spin_lock_save(&debug_mutex_lock, flags); \ | 43 | local_irq_save(flags); \ |
70 | spin_lock(lock); \ | 44 | __raw_spin_lock(&(lock)->raw_lock); \ |
71 | DEBUG_LOCKS_WARN_ON(l->magic != l); \ | 45 | DEBUG_LOCKS_WARN_ON(l->magic != l); \ |
72 | } while (0) | 46 | } while (0) |
73 | 47 | ||
74 | #define spin_unlock_mutex(lock, flags) \ | 48 | #define spin_unlock_mutex(lock, flags) \ |
75 | do { \ | 49 | do { \ |
76 | spin_unlock(lock); \ | 50 | __raw_spin_unlock(&(lock)->raw_lock); \ |
77 | debug_spin_unlock_restore(&debug_mutex_lock, flags); \ | 51 | local_irq_restore(flags); \ |
52 | preempt_check_resched(); \ | ||
78 | } while (0) | 53 | } while (0) |
79 | |||
80 | #define DEBUG_OFF() \ | ||
81 | do { \ | ||
82 | if (debug_mutex_on) { \ | ||
83 | debug_mutex_on = 0; \ | ||
84 | console_verbose(); \ | ||
85 | if (spin_is_locked(&debug_mutex_lock)) \ | ||
86 | spin_unlock(&debug_mutex_lock); \ | ||
87 | } \ | ||
88 | } while (0) | ||
89 | |||
90 | #define DEBUG_BUG() \ | ||
91 | do { \ | ||
92 | if (debug_mutex_on) { \ | ||
93 | DEBUG_OFF(); \ | ||
94 | BUG(); \ | ||
95 | } \ | ||
96 | } while (0) | ||
97 | |||
98 | #define DEBUG_LOCKS_WARN_ON(c) \ | ||
99 | do { \ | ||
100 | if (unlikely(c && debug_mutex_on)) { \ | ||
101 | DEBUG_OFF(); \ | ||
102 | WARN_ON(1); \ | ||
103 | } \ | ||
104 | } while (0) | ||
105 | |||
106 | #ifdef CONFIG_SMP | ||
107 | # define SMP_DEBUG_LOCKS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) | ||
108 | #else | ||
109 | # define SMP_DEBUG_LOCKS_WARN_ON(c) do { } while (0) | ||
110 | #endif | ||
111 | |||