blob: 3de2ccf48ac696d9fb62bc3192cad7792e263662 [file] [log] [blame]
Ingo Molnarfb1c8f92005-09-10 00:25:56 -07001/*
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
Ingo Molnarfb1c8f92005-09-10 00:25:56 -07009#include <linux/spinlock.h>
10#include <linux/interrupt.h>
Ingo Molnar9a11b49a2006-07-03 00:24:33 -070011#include <linux/debug_locks.h>
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070012#include <linux/delay.h>
Ingo Molnar9a11b49a2006-07-03 00:24:33 -070013#include <linux/module.h>
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070014
15static void spin_bug(spinlock_t *lock, const char *msg)
16{
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070017 struct task_struct *owner = NULL;
18
Ingo Molnar9a11b49a2006-07-03 00:24:33 -070019 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();
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070034}
35
36#define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg)
37
Ingo Molnar9a11b49a2006-07-03 00:24:33 -070038static inline void
39debug_spin_lock_before(spinlock_t *lock)
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070040{
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
47static inline void debug_spin_lock_after(spinlock_t *lock)
48{
49 lock->owner_cpu = raw_smp_processor_id();
50 lock->owner = current;
51}
52
53static 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
64static 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++) {
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070071 if (__raw_spin_trylock(&lock->raw_lock))
72 return;
Ingo Molnare0a60292006-02-07 12:58:54 -080073 __delay(1);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070074 }
75 /* lockup suspected: */
76 if (print_once) {
77 print_once = 0;
Dave Jones51989b92006-01-09 20:51:32 -080078 printk(KERN_EMERG "BUG: spinlock lockup on CPU#%d, "
79 "%s/%d, %p\n",
Ingo Molnarbb44f112005-12-20 11:54:17 +010080 raw_smp_processor_id(), current->comm,
81 current->pid, lock);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070082 dump_stack();
83 }
84 }
85}
86
87void _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
95int _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
110void _raw_spin_unlock(spinlock_t *lock)
111{
112 debug_spin_unlock(lock);
113 __raw_spin_unlock(&lock->raw_lock);
114}
115
116static void rwlock_bug(rwlock_t *lock, const char *msg)
117{
Ingo Molnar9a11b49a2006-07-03 00:24:33 -0700118 if (!debug_locks_off())
119 return;
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700120
Ingo Molnar9a11b49a2006-07-03 00:24:33 -0700121 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();
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700125}
126
127#define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
128
129static 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++) {
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700136 if (__raw_read_trylock(&lock->raw_lock))
137 return;
Ingo Molnare0a60292006-02-07 12:58:54 -0800138 __delay(1);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700139 }
140 /* lockup suspected: */
141 if (print_once) {
142 print_once = 0;
Dave Jones51989b92006-01-09 20:51:32 -0800143 printk(KERN_EMERG "BUG: read-lock lockup on CPU#%d, "
144 "%s/%d, %p\n",
Ingo Molnarbb44f112005-12-20 11:54:17 +0100145 raw_smp_processor_id(), current->comm,
146 current->pid, lock);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700147 dump_stack();
148 }
149 }
150}
151
152void _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
159int _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
172void _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
178static 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
186static inline void debug_write_lock_after(rwlock_t *lock)
187{
188 lock->owner_cpu = raw_smp_processor_id();
189 lock->owner = current;
190}
191
192static 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
202static 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++) {
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700209 if (__raw_write_trylock(&lock->raw_lock))
210 return;
Ingo Molnare0a60292006-02-07 12:58:54 -0800211 __delay(1);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700212 }
213 /* lockup suspected: */
214 if (print_once) {
215 print_once = 0;
Dave Jones51989b92006-01-09 20:51:32 -0800216 printk(KERN_EMERG "BUG: write-lock lockup on CPU#%d, "
217 "%s/%d, %p\n",
Ingo Molnarbb44f112005-12-20 11:54:17 +0100218 raw_smp_processor_id(), current->comm,
219 current->pid, lock);
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700220 dump_stack();
221 }
222 }
223}
224
225void _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
233int _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
248void _raw_write_unlock(rwlock_t *lock)
249{
250 debug_write_unlock(lock);
251 __raw_write_unlock(&lock->raw_lock);
252}