160fc2874SPeter Zijlstra /*
260fc2874SPeter Zijlstra  * Copyright 2005, Red Hat, Inc., Ingo Molnar
360fc2874SPeter Zijlstra  * Released under the General Public License (GPL).
460fc2874SPeter Zijlstra  *
560fc2874SPeter Zijlstra  * This file contains the spinlock/rwlock implementations for
660fc2874SPeter Zijlstra  * DEBUG_SPINLOCK.
760fc2874SPeter Zijlstra  */
860fc2874SPeter Zijlstra 
960fc2874SPeter Zijlstra #include <linux/spinlock.h>
1060fc2874SPeter Zijlstra #include <linux/nmi.h>
1160fc2874SPeter Zijlstra #include <linux/interrupt.h>
1260fc2874SPeter Zijlstra #include <linux/debug_locks.h>
1360fc2874SPeter Zijlstra #include <linux/delay.h>
1460fc2874SPeter Zijlstra #include <linux/export.h>
1560fc2874SPeter Zijlstra 
__raw_spin_lock_init(raw_spinlock_t * lock,const char * name,struct lock_class_key * key,short inner)1660fc2874SPeter Zijlstra void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
17de8f5e4fSPeter Zijlstra 			  struct lock_class_key *key, short inner)
1860fc2874SPeter Zijlstra {
1960fc2874SPeter Zijlstra #ifdef CONFIG_DEBUG_LOCK_ALLOC
2060fc2874SPeter Zijlstra 	/*
2160fc2874SPeter Zijlstra 	 * Make sure we are not reinitializing a held lock:
2260fc2874SPeter Zijlstra 	 */
2360fc2874SPeter Zijlstra 	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
24de8f5e4fSPeter Zijlstra 	lockdep_init_map_wait(&lock->dep_map, name, key, 0, inner);
2560fc2874SPeter Zijlstra #endif
2660fc2874SPeter Zijlstra 	lock->raw_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
2760fc2874SPeter Zijlstra 	lock->magic = SPINLOCK_MAGIC;
2860fc2874SPeter Zijlstra 	lock->owner = SPINLOCK_OWNER_INIT;
2960fc2874SPeter Zijlstra 	lock->owner_cpu = -1;
3060fc2874SPeter Zijlstra }
3160fc2874SPeter Zijlstra 
3260fc2874SPeter Zijlstra EXPORT_SYMBOL(__raw_spin_lock_init);
3360fc2874SPeter Zijlstra 
34*8282947fSThomas Gleixner #ifndef CONFIG_PREEMPT_RT
__rwlock_init(rwlock_t * lock,const char * name,struct lock_class_key * key)3560fc2874SPeter Zijlstra void __rwlock_init(rwlock_t *lock, const char *name,
3660fc2874SPeter Zijlstra 		   struct lock_class_key *key)
3760fc2874SPeter Zijlstra {
3860fc2874SPeter Zijlstra #ifdef CONFIG_DEBUG_LOCK_ALLOC
3960fc2874SPeter Zijlstra 	/*
4060fc2874SPeter Zijlstra 	 * Make sure we are not reinitializing a held lock:
4160fc2874SPeter Zijlstra 	 */
4260fc2874SPeter Zijlstra 	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
43de8f5e4fSPeter Zijlstra 	lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_CONFIG);
4460fc2874SPeter Zijlstra #endif
4560fc2874SPeter Zijlstra 	lock->raw_lock = (arch_rwlock_t) __ARCH_RW_LOCK_UNLOCKED;
4660fc2874SPeter Zijlstra 	lock->magic = RWLOCK_MAGIC;
4760fc2874SPeter Zijlstra 	lock->owner = SPINLOCK_OWNER_INIT;
4860fc2874SPeter Zijlstra 	lock->owner_cpu = -1;
4960fc2874SPeter Zijlstra }
5060fc2874SPeter Zijlstra 
5160fc2874SPeter Zijlstra EXPORT_SYMBOL(__rwlock_init);
52*8282947fSThomas Gleixner #endif
5360fc2874SPeter Zijlstra 
spin_dump(raw_spinlock_t * lock,const char * msg)5460fc2874SPeter Zijlstra static void spin_dump(raw_spinlock_t *lock, const char *msg)
5560fc2874SPeter Zijlstra {
561a365e82SMarco Elver 	struct task_struct *owner = READ_ONCE(lock->owner);
5760fc2874SPeter Zijlstra 
581a365e82SMarco Elver 	if (owner == SPINLOCK_OWNER_INIT)
591a365e82SMarco Elver 		owner = NULL;
6060fc2874SPeter Zijlstra 	printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n",
6160fc2874SPeter Zijlstra 		msg, raw_smp_processor_id(),
6260fc2874SPeter Zijlstra 		current->comm, task_pid_nr(current));
6360fc2874SPeter Zijlstra 	printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, "
6460fc2874SPeter Zijlstra 			".owner_cpu: %d\n",
651a365e82SMarco Elver 		lock, READ_ONCE(lock->magic),
6660fc2874SPeter Zijlstra 		owner ? owner->comm : "<none>",
6760fc2874SPeter Zijlstra 		owner ? task_pid_nr(owner) : -1,
681a365e82SMarco Elver 		READ_ONCE(lock->owner_cpu));
6960fc2874SPeter Zijlstra 	dump_stack();
7060fc2874SPeter Zijlstra }
7160fc2874SPeter Zijlstra 
spin_bug(raw_spinlock_t * lock,const char * msg)7260fc2874SPeter Zijlstra static void spin_bug(raw_spinlock_t *lock, const char *msg)
7360fc2874SPeter Zijlstra {
7460fc2874SPeter Zijlstra 	if (!debug_locks_off())
7560fc2874SPeter Zijlstra 		return;
7660fc2874SPeter Zijlstra 
7760fc2874SPeter Zijlstra 	spin_dump(lock, msg);
7860fc2874SPeter Zijlstra }
7960fc2874SPeter Zijlstra 
8060fc2874SPeter Zijlstra #define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg)
8160fc2874SPeter Zijlstra 
8260fc2874SPeter Zijlstra static inline void
debug_spin_lock_before(raw_spinlock_t * lock)8360fc2874SPeter Zijlstra debug_spin_lock_before(raw_spinlock_t *lock)
8460fc2874SPeter Zijlstra {
851a365e82SMarco Elver 	SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic");
861a365e82SMarco Elver 	SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion");
871a365e82SMarco Elver 	SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(),
8860fc2874SPeter Zijlstra 							lock, "cpu recursion");
8960fc2874SPeter Zijlstra }
9060fc2874SPeter Zijlstra 
debug_spin_lock_after(raw_spinlock_t * lock)9160fc2874SPeter Zijlstra static inline void debug_spin_lock_after(raw_spinlock_t *lock)
9260fc2874SPeter Zijlstra {
931a365e82SMarco Elver 	WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
941a365e82SMarco Elver 	WRITE_ONCE(lock->owner, current);
9560fc2874SPeter Zijlstra }
9660fc2874SPeter Zijlstra 
debug_spin_unlock(raw_spinlock_t * lock)9760fc2874SPeter Zijlstra static inline void debug_spin_unlock(raw_spinlock_t *lock)
9860fc2874SPeter Zijlstra {
9960fc2874SPeter Zijlstra 	SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic");
10060fc2874SPeter Zijlstra 	SPIN_BUG_ON(!raw_spin_is_locked(lock), lock, "already unlocked");
10160fc2874SPeter Zijlstra 	SPIN_BUG_ON(lock->owner != current, lock, "wrong owner");
10260fc2874SPeter Zijlstra 	SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
10360fc2874SPeter Zijlstra 							lock, "wrong CPU");
1041a365e82SMarco Elver 	WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
1051a365e82SMarco Elver 	WRITE_ONCE(lock->owner_cpu, -1);
10660fc2874SPeter Zijlstra }
10760fc2874SPeter Zijlstra 
10860fc2874SPeter Zijlstra /*
109bc88c10dSWaiman Long  * We are now relying on the NMI watchdog to detect lockup instead of doing
110bc88c10dSWaiman Long  * the detection here with an unfair lock which can cause problem of its own.
11160fc2874SPeter Zijlstra  */
do_raw_spin_lock(raw_spinlock_t * lock)11260fc2874SPeter Zijlstra void do_raw_spin_lock(raw_spinlock_t *lock)
11360fc2874SPeter Zijlstra {
11460fc2874SPeter Zijlstra 	debug_spin_lock_before(lock);
115bc88c10dSWaiman Long 	arch_spin_lock(&lock->raw_lock);
11660ca1e5aSWill Deacon 	mmiowb_spin_lock();
11760fc2874SPeter Zijlstra 	debug_spin_lock_after(lock);
11860fc2874SPeter Zijlstra }
11960fc2874SPeter Zijlstra 
do_raw_spin_trylock(raw_spinlock_t * lock)12060fc2874SPeter Zijlstra int do_raw_spin_trylock(raw_spinlock_t *lock)
12160fc2874SPeter Zijlstra {
12260fc2874SPeter Zijlstra 	int ret = arch_spin_trylock(&lock->raw_lock);
12360fc2874SPeter Zijlstra 
12460ca1e5aSWill Deacon 	if (ret) {
12560ca1e5aSWill Deacon 		mmiowb_spin_lock();
12660fc2874SPeter Zijlstra 		debug_spin_lock_after(lock);
12760ca1e5aSWill Deacon 	}
12860fc2874SPeter Zijlstra #ifndef CONFIG_SMP
12960fc2874SPeter Zijlstra 	/*
13060fc2874SPeter Zijlstra 	 * Must not happen on UP:
13160fc2874SPeter Zijlstra 	 */
13260fc2874SPeter Zijlstra 	SPIN_BUG_ON(!ret, lock, "trylock failure on UP");
13360fc2874SPeter Zijlstra #endif
13460fc2874SPeter Zijlstra 	return ret;
13560fc2874SPeter Zijlstra }
13660fc2874SPeter Zijlstra 
do_raw_spin_unlock(raw_spinlock_t * lock)13760fc2874SPeter Zijlstra void do_raw_spin_unlock(raw_spinlock_t *lock)
13860fc2874SPeter Zijlstra {
13960ca1e5aSWill Deacon 	mmiowb_spin_unlock();
14060fc2874SPeter Zijlstra 	debug_spin_unlock(lock);
14160fc2874SPeter Zijlstra 	arch_spin_unlock(&lock->raw_lock);
14260fc2874SPeter Zijlstra }
14360fc2874SPeter Zijlstra 
144*8282947fSThomas Gleixner #ifndef CONFIG_PREEMPT_RT
rwlock_bug(rwlock_t * lock,const char * msg)14560fc2874SPeter Zijlstra static void rwlock_bug(rwlock_t *lock, const char *msg)
14660fc2874SPeter Zijlstra {
14760fc2874SPeter Zijlstra 	if (!debug_locks_off())
14860fc2874SPeter Zijlstra 		return;
14960fc2874SPeter Zijlstra 
15060fc2874SPeter Zijlstra 	printk(KERN_EMERG "BUG: rwlock %s on CPU#%d, %s/%d, %p\n",
15160fc2874SPeter Zijlstra 		msg, raw_smp_processor_id(), current->comm,
15260fc2874SPeter Zijlstra 		task_pid_nr(current), lock);
15360fc2874SPeter Zijlstra 	dump_stack();
15460fc2874SPeter Zijlstra }
15560fc2874SPeter Zijlstra 
15660fc2874SPeter Zijlstra #define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
15760fc2874SPeter Zijlstra 
do_raw_read_lock(rwlock_t * lock)15860fc2874SPeter Zijlstra void do_raw_read_lock(rwlock_t *lock)
15960fc2874SPeter Zijlstra {
16060fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
16160fc2874SPeter Zijlstra 	arch_read_lock(&lock->raw_lock);
16260fc2874SPeter Zijlstra }
16360fc2874SPeter Zijlstra 
do_raw_read_trylock(rwlock_t * lock)16460fc2874SPeter Zijlstra int do_raw_read_trylock(rwlock_t *lock)
16560fc2874SPeter Zijlstra {
16660fc2874SPeter Zijlstra 	int ret = arch_read_trylock(&lock->raw_lock);
16760fc2874SPeter Zijlstra 
16860fc2874SPeter Zijlstra #ifndef CONFIG_SMP
16960fc2874SPeter Zijlstra 	/*
17060fc2874SPeter Zijlstra 	 * Must not happen on UP:
17160fc2874SPeter Zijlstra 	 */
17260fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP");
17360fc2874SPeter Zijlstra #endif
17460fc2874SPeter Zijlstra 	return ret;
17560fc2874SPeter Zijlstra }
17660fc2874SPeter Zijlstra 
do_raw_read_unlock(rwlock_t * lock)17760fc2874SPeter Zijlstra void do_raw_read_unlock(rwlock_t *lock)
17860fc2874SPeter Zijlstra {
17960fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
18060fc2874SPeter Zijlstra 	arch_read_unlock(&lock->raw_lock);
18160fc2874SPeter Zijlstra }
18260fc2874SPeter Zijlstra 
debug_write_lock_before(rwlock_t * lock)18360fc2874SPeter Zijlstra static inline void debug_write_lock_before(rwlock_t *lock)
18460fc2874SPeter Zijlstra {
18560fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
18660fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->owner == current, lock, "recursion");
18760fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->owner_cpu == raw_smp_processor_id(),
18860fc2874SPeter Zijlstra 							lock, "cpu recursion");
18960fc2874SPeter Zijlstra }
19060fc2874SPeter Zijlstra 
debug_write_lock_after(rwlock_t * lock)19160fc2874SPeter Zijlstra static inline void debug_write_lock_after(rwlock_t *lock)
19260fc2874SPeter Zijlstra {
1931a365e82SMarco Elver 	WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
1941a365e82SMarco Elver 	WRITE_ONCE(lock->owner, current);
19560fc2874SPeter Zijlstra }
19660fc2874SPeter Zijlstra 
debug_write_unlock(rwlock_t * lock)19760fc2874SPeter Zijlstra static inline void debug_write_unlock(rwlock_t *lock)
19860fc2874SPeter Zijlstra {
19960fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
20060fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner");
20160fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
20260fc2874SPeter Zijlstra 							lock, "wrong CPU");
2031a365e82SMarco Elver 	WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
2041a365e82SMarco Elver 	WRITE_ONCE(lock->owner_cpu, -1);
20560fc2874SPeter Zijlstra }
20660fc2874SPeter Zijlstra 
do_raw_write_lock(rwlock_t * lock)20760fc2874SPeter Zijlstra void do_raw_write_lock(rwlock_t *lock)
20860fc2874SPeter Zijlstra {
20960fc2874SPeter Zijlstra 	debug_write_lock_before(lock);
21060fc2874SPeter Zijlstra 	arch_write_lock(&lock->raw_lock);
21160fc2874SPeter Zijlstra 	debug_write_lock_after(lock);
21260fc2874SPeter Zijlstra }
21360fc2874SPeter Zijlstra 
do_raw_write_trylock(rwlock_t * lock)21460fc2874SPeter Zijlstra int do_raw_write_trylock(rwlock_t *lock)
21560fc2874SPeter Zijlstra {
21660fc2874SPeter Zijlstra 	int ret = arch_write_trylock(&lock->raw_lock);
21760fc2874SPeter Zijlstra 
21860fc2874SPeter Zijlstra 	if (ret)
21960fc2874SPeter Zijlstra 		debug_write_lock_after(lock);
22060fc2874SPeter Zijlstra #ifndef CONFIG_SMP
22160fc2874SPeter Zijlstra 	/*
22260fc2874SPeter Zijlstra 	 * Must not happen on UP:
22360fc2874SPeter Zijlstra 	 */
22460fc2874SPeter Zijlstra 	RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP");
22560fc2874SPeter Zijlstra #endif
22660fc2874SPeter Zijlstra 	return ret;
22760fc2874SPeter Zijlstra }
22860fc2874SPeter Zijlstra 
do_raw_write_unlock(rwlock_t * lock)22960fc2874SPeter Zijlstra void do_raw_write_unlock(rwlock_t *lock)
23060fc2874SPeter Zijlstra {
23160fc2874SPeter Zijlstra 	debug_write_unlock(lock);
23260fc2874SPeter Zijlstra 	arch_write_unlock(&lock->raw_lock);
23360fc2874SPeter Zijlstra }
234*8282947fSThomas Gleixner 
235*8282947fSThomas Gleixner #endif /* !CONFIG_PREEMPT_RT */
236