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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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