]>
Commit | Line | Data |
---|---|---|
fb1c8f93 IM |
1 | /* |
2 | * Copyright 2005, Red Hat, Inc., Ingo Molnar | |
3 | * Released under the General Public License (GPL). | |
4 | * | |
5 | * This file contains the spinlock/rwlock implementations for | |
6 | * DEBUG_SPINLOCK. | |
7 | */ | |
8 | ||
fb1c8f93 IM |
9 | #include <linux/spinlock.h> |
10 | #include <linux/interrupt.h> | |
9a11b49a | 11 | #include <linux/debug_locks.h> |
fb1c8f93 | 12 | #include <linux/delay.h> |
9a11b49a | 13 | #include <linux/module.h> |
fb1c8f93 IM |
14 | |
15 | static void spin_bug(spinlock_t *lock, const char *msg) | |
16 | { | |
fb1c8f93 IM |
17 | struct task_struct *owner = NULL; |
18 | ||
9a11b49a IM |
19 | if (!debug_locks_off()) |
20 | return; | |
21 | ||
22 | if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT) | |
23 | owner = lock->owner; | |
24 | printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n", | |
25 | msg, raw_smp_processor_id(), | |
26 | current->comm, current->pid); | |
27 | printk(KERN_EMERG " lock: %p, .magic: %08x, .owner: %s/%d, " | |
28 | ".owner_cpu: %d\n", | |
29 | lock, lock->magic, | |
30 | owner ? owner->comm : "<none>", | |
31 | owner ? owner->pid : -1, | |
32 | lock->owner_cpu); | |
33 | dump_stack(); | |
fb1c8f93 IM |
34 | } |
35 | ||
36 | #define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg) | |
37 | ||
9a11b49a IM |
38 | static inline void |
39 | debug_spin_lock_before(spinlock_t *lock) | |
fb1c8f93 IM |
40 | { |
41 | SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); | |
42 | SPIN_BUG_ON(lock->owner == current, lock, "recursion"); | |
43 | SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), | |
44 | lock, "cpu recursion"); | |
45 | } | |
46 | ||
47 | static inline void debug_spin_lock_after(spinlock_t *lock) | |
48 | { | |
49 | lock->owner_cpu = raw_smp_processor_id(); | |
50 | lock->owner = current; | |
51 | } | |
52 | ||
53 | static inline void debug_spin_unlock(spinlock_t *lock) | |
54 | { | |
55 | SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); | |
56 | SPIN_BUG_ON(!spin_is_locked(lock), lock, "already unlocked"); | |
57 | SPIN_BUG_ON(lock->owner != current, lock, "wrong owner"); | |
58 | SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), | |
59 | lock, "wrong CPU"); | |
60 | lock->owner = SPINLOCK_OWNER_INIT; | |
61 | lock->owner_cpu = -1; | |
62 | } | |
63 | ||
64 | static void __spin_lock_debug(spinlock_t *lock) | |
65 | { | |
66 | int print_once = 1; | |
67 | u64 i; | |
68 | ||
69 | for (;;) { | |
70 | for (i = 0; i < loops_per_jiffy * HZ; i++) { | |
fb1c8f93 IM |
71 | if (__raw_spin_trylock(&lock->raw_lock)) |
72 | return; | |
e0a60296 | 73 | __delay(1); |
fb1c8f93 IM |
74 | } |
75 | /* lockup suspected: */ | |
76 | if (print_once) { | |
77 | print_once = 0; | |
51989b9f DJ |
78 | printk(KERN_EMERG "BUG: spinlock lockup on CPU#%d, " |
79 | "%s/%d, %p\n", | |
bb44f116 IM |
80 | raw_smp_processor_id(), current->comm, |
81 | current->pid, lock); | |
fb1c8f93 IM |
82 | dump_stack(); |
83 | } | |
84 | } | |
85 | } | |
86 | ||
87 | void _raw_spin_lock(spinlock_t *lock) | |
88 | { | |
89 | debug_spin_lock_before(lock); | |
90 | if (unlikely(!__raw_spin_trylock(&lock->raw_lock))) | |
91 | __spin_lock_debug(lock); | |
92 | debug_spin_lock_after(lock); | |
93 | } | |
94 | ||
95 | int _raw_spin_trylock(spinlock_t *lock) | |
96 | { | |
97 | int ret = __raw_spin_trylock(&lock->raw_lock); | |
98 | ||
99 | if (ret) | |
100 | debug_spin_lock_after(lock); | |
101 | #ifndef CONFIG_SMP | |
102 | /* | |
103 | * Must not happen on UP: | |
104 | */ | |
105 | SPIN_BUG_ON(!ret, lock, "trylock failure on UP"); | |
106 | #endif | |
107 | return ret; | |
108 | } | |
109 | ||
110 | void _raw_spin_unlock(spinlock_t *lock) | |
111 | { | |
112 | debug_spin_unlock(lock); | |
113 | __raw_spin_unlock(&lock->raw_lock); | |
114 | } | |
115 | ||
116 | static void rwlock_bug(rwlock_t *lock, const char *msg) | |
117 | { | |
9a11b49a IM |
118 | if (!debug_locks_off()) |
119 | return; | |
120 | ||
121 | printk(KERN_EMERG "BUG: rwlock %s on CPU#%d, %s/%d, %p\n", | |
122 | msg, raw_smp_processor_id(), current->comm, | |
123 | current->pid, lock); | |
124 | dump_stack(); | |
fb1c8f93 IM |
125 | } |
126 | ||
127 | #define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg) | |
128 | ||
129 | static void __read_lock_debug(rwlock_t *lock) | |
130 | { | |
131 | int print_once = 1; | |
132 | u64 i; | |
133 | ||
134 | for (;;) { | |
135 | for (i = 0; i < loops_per_jiffy * HZ; i++) { | |
fb1c8f93 IM |
136 | if (__raw_read_trylock(&lock->raw_lock)) |
137 | return; | |
e0a60296 | 138 | __delay(1); |
fb1c8f93 IM |
139 | } |
140 | /* lockup suspected: */ | |
141 | if (print_once) { | |
142 | print_once = 0; | |
51989b9f DJ |
143 | printk(KERN_EMERG "BUG: read-lock lockup on CPU#%d, " |
144 | "%s/%d, %p\n", | |
bb44f116 IM |
145 | raw_smp_processor_id(), current->comm, |
146 | current->pid, lock); | |
fb1c8f93 IM |
147 | dump_stack(); |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | void _raw_read_lock(rwlock_t *lock) | |
153 | { | |
154 | RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); | |
155 | if (unlikely(!__raw_read_trylock(&lock->raw_lock))) | |
156 | __read_lock_debug(lock); | |
157 | } | |
158 | ||
159 | int _raw_read_trylock(rwlock_t *lock) | |
160 | { | |
161 | int ret = __raw_read_trylock(&lock->raw_lock); | |
162 | ||
163 | #ifndef CONFIG_SMP | |
164 | /* | |
165 | * Must not happen on UP: | |
166 | */ | |
167 | RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP"); | |
168 | #endif | |
169 | return ret; | |
170 | } | |
171 | ||
172 | void _raw_read_unlock(rwlock_t *lock) | |
173 | { | |
174 | RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); | |
175 | __raw_read_unlock(&lock->raw_lock); | |
176 | } | |
177 | ||
178 | static inline void debug_write_lock_before(rwlock_t *lock) | |
179 | { | |
180 | RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); | |
181 | RWLOCK_BUG_ON(lock->owner == current, lock, "recursion"); | |
182 | RWLOCK_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), | |
183 | lock, "cpu recursion"); | |
184 | } | |
185 | ||
186 | static inline void debug_write_lock_after(rwlock_t *lock) | |
187 | { | |
188 | lock->owner_cpu = raw_smp_processor_id(); | |
189 | lock->owner = current; | |
190 | } | |
191 | ||
192 | static inline void debug_write_unlock(rwlock_t *lock) | |
193 | { | |
194 | RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); | |
195 | RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner"); | |
196 | RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), | |
197 | lock, "wrong CPU"); | |
198 | lock->owner = SPINLOCK_OWNER_INIT; | |
199 | lock->owner_cpu = -1; | |
200 | } | |
201 | ||
202 | static void __write_lock_debug(rwlock_t *lock) | |
203 | { | |
204 | int print_once = 1; | |
205 | u64 i; | |
206 | ||
207 | for (;;) { | |
208 | for (i = 0; i < loops_per_jiffy * HZ; i++) { | |
fb1c8f93 IM |
209 | if (__raw_write_trylock(&lock->raw_lock)) |
210 | return; | |
e0a60296 | 211 | __delay(1); |
fb1c8f93 IM |
212 | } |
213 | /* lockup suspected: */ | |
214 | if (print_once) { | |
215 | print_once = 0; | |
51989b9f DJ |
216 | printk(KERN_EMERG "BUG: write-lock lockup on CPU#%d, " |
217 | "%s/%d, %p\n", | |
bb44f116 IM |
218 | raw_smp_processor_id(), current->comm, |
219 | current->pid, lock); | |
fb1c8f93 IM |
220 | dump_stack(); |
221 | } | |
222 | } | |
223 | } | |
224 | ||
225 | void _raw_write_lock(rwlock_t *lock) | |
226 | { | |
227 | debug_write_lock_before(lock); | |
228 | if (unlikely(!__raw_write_trylock(&lock->raw_lock))) | |
229 | __write_lock_debug(lock); | |
230 | debug_write_lock_after(lock); | |
231 | } | |
232 | ||
233 | int _raw_write_trylock(rwlock_t *lock) | |
234 | { | |
235 | int ret = __raw_write_trylock(&lock->raw_lock); | |
236 | ||
237 | if (ret) | |
238 | debug_write_lock_after(lock); | |
239 | #ifndef CONFIG_SMP | |
240 | /* | |
241 | * Must not happen on UP: | |
242 | */ | |
243 | RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP"); | |
244 | #endif | |
245 | return ret; | |
246 | } | |
247 | ||
248 | void _raw_write_unlock(rwlock_t *lock) | |
249 | { | |
250 | debug_write_unlock(lock); | |
251 | __raw_write_unlock(&lock->raw_lock); | |
252 | } |