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.c | |
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.c')
-rw-r--r-- | kernel/mutex-debug.c | 51 |
1 files changed, 7 insertions, 44 deletions
diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index a92de145ed0d..5569766a1ea2 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c | |||
@@ -20,52 +20,19 @@ | |||
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/kallsyms.h> | 21 | #include <linux/kallsyms.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/debug_locks.h> | ||
23 | 24 | ||
24 | #include "mutex-debug.h" | 25 | #include "mutex-debug.h" |
25 | 26 | ||
26 | /* | 27 | /* |
27 | * We need a global lock when we walk through the multi-process | ||
28 | * lock tree. Only used in the deadlock-debugging case. | ||
29 | */ | ||
30 | DEFINE_SPINLOCK(debug_mutex_lock); | ||
31 | |||
32 | /* | ||
33 | * All locks held by all tasks, in a single global list: | ||
34 | */ | ||
35 | LIST_HEAD(debug_mutex_held_locks); | ||
36 | |||
37 | /* | ||
38 | * In the debug case we carry the caller's instruction pointer into | ||
39 | * other functions, but we dont want the function argument overhead | ||
40 | * in the nondebug case - hence these macros: | ||
41 | */ | ||
42 | #define __IP_DECL__ , unsigned long ip | ||
43 | #define __IP__ , ip | ||
44 | #define __RET_IP__ , (unsigned long)__builtin_return_address(0) | ||
45 | |||
46 | /* | ||
47 | * "mutex debugging enabled" flag. We turn it off when we detect | ||
48 | * the first problem because we dont want to recurse back | ||
49 | * into the tracing code when doing error printk or | ||
50 | * executing a BUG(): | ||
51 | */ | ||
52 | int debug_mutex_on = 1; | ||
53 | |||
54 | /* | ||
55 | * Must be called with lock->wait_lock held. | 28 | * Must be called with lock->wait_lock held. |
56 | */ | 29 | */ |
57 | void debug_mutex_set_owner(struct mutex *lock, | 30 | void debug_mutex_set_owner(struct mutex *lock, struct thread_info *new_owner) |
58 | struct thread_info *new_owner __IP_DECL__) | ||
59 | { | 31 | { |
60 | lock->owner = new_owner; | 32 | lock->owner = new_owner; |
61 | DEBUG_LOCKS_WARN_ON(!list_empty(&lock->held_list)); | ||
62 | if (debug_mutex_on) { | ||
63 | list_add_tail(&lock->held_list, &debug_mutex_held_locks); | ||
64 | lock->acquire_ip = ip; | ||
65 | } | ||
66 | } | 33 | } |
67 | 34 | ||
68 | void debug_mutex_init_waiter(struct mutex_waiter *waiter) | 35 | void debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter) |
69 | { | 36 | { |
70 | memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter)); | 37 | memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter)); |
71 | waiter->magic = waiter; | 38 | waiter->magic = waiter; |
@@ -87,9 +54,10 @@ void debug_mutex_free_waiter(struct mutex_waiter *waiter) | |||
87 | } | 54 | } |
88 | 55 | ||
89 | void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, | 56 | void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, |
90 | struct thread_info *ti __IP_DECL__) | 57 | struct thread_info *ti) |
91 | { | 58 | { |
92 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); | 59 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); |
60 | |||
93 | /* Mark the current thread as blocked on the lock: */ | 61 | /* Mark the current thread as blocked on the lock: */ |
94 | ti->task->blocked_on = waiter; | 62 | ti->task->blocked_on = waiter; |
95 | waiter->lock = lock; | 63 | waiter->lock = lock; |
@@ -109,13 +77,10 @@ void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, | |||
109 | 77 | ||
110 | void debug_mutex_unlock(struct mutex *lock) | 78 | void debug_mutex_unlock(struct mutex *lock) |
111 | { | 79 | { |
80 | DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); | ||
112 | DEBUG_LOCKS_WARN_ON(lock->magic != lock); | 81 | DEBUG_LOCKS_WARN_ON(lock->magic != lock); |
113 | DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); | 82 | DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); |
114 | DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); | 83 | DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); |
115 | if (debug_mutex_on) { | ||
116 | DEBUG_LOCKS_WARN_ON(list_empty(&lock->held_list)); | ||
117 | list_del_init(&lock->held_list); | ||
118 | } | ||
119 | } | 84 | } |
120 | 85 | ||
121 | void debug_mutex_init(struct mutex *lock, const char *name) | 86 | void debug_mutex_init(struct mutex *lock, const char *name) |
@@ -123,10 +88,8 @@ void debug_mutex_init(struct mutex *lock, const char *name) | |||
123 | /* | 88 | /* |
124 | * Make sure we are not reinitializing a held lock: | 89 | * Make sure we are not reinitializing a held lock: |
125 | */ | 90 | */ |
126 | mutex_debug_check_no_locks_freed((void *)lock, sizeof(*lock)); | 91 | debug_check_no_locks_freed((void *)lock, sizeof(*lock)); |
127 | lock->owner = NULL; | 92 | lock->owner = NULL; |
128 | INIT_LIST_HEAD(&lock->held_list); | ||
129 | lock->name = name; | ||
130 | lock->magic = lock; | 93 | lock->magic = lock; |
131 | } | 94 | } |
132 | 95 | ||