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>
15*f551103cSKent Overstreet #include <linux/pid.h>
1660fc2874SPeter Zijlstra
__raw_spin_lock_init(raw_spinlock_t * lock,const char * name,struct lock_class_key * key,short inner)1760fc2874SPeter Zijlstra void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
18de8f5e4fSPeter Zijlstra struct lock_class_key *key, short inner)
1960fc2874SPeter Zijlstra {
2060fc2874SPeter Zijlstra #ifdef CONFIG_DEBUG_LOCK_ALLOC
2160fc2874SPeter Zijlstra /*
2260fc2874SPeter Zijlstra * Make sure we are not reinitializing a held lock:
2360fc2874SPeter Zijlstra */
2460fc2874SPeter Zijlstra debug_check_no_locks_freed((void *)lock, sizeof(*lock));
25de8f5e4fSPeter Zijlstra lockdep_init_map_wait(&lock->dep_map, name, key, 0, inner);
2660fc2874SPeter Zijlstra #endif
2760fc2874SPeter Zijlstra lock->raw_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
2860fc2874SPeter Zijlstra lock->magic = SPINLOCK_MAGIC;
2960fc2874SPeter Zijlstra lock->owner = SPINLOCK_OWNER_INIT;
3060fc2874SPeter Zijlstra lock->owner_cpu = -1;
3160fc2874SPeter Zijlstra }
3260fc2874SPeter Zijlstra
3360fc2874SPeter Zijlstra EXPORT_SYMBOL(__raw_spin_lock_init);
3460fc2874SPeter Zijlstra
358282947fSThomas Gleixner #ifndef CONFIG_PREEMPT_RT
__rwlock_init(rwlock_t * lock,const char * name,struct lock_class_key * key)3660fc2874SPeter Zijlstra void __rwlock_init(rwlock_t *lock, const char *name,
3760fc2874SPeter Zijlstra struct lock_class_key *key)
3860fc2874SPeter Zijlstra {
3960fc2874SPeter Zijlstra #ifdef CONFIG_DEBUG_LOCK_ALLOC
4060fc2874SPeter Zijlstra /*
4160fc2874SPeter Zijlstra * Make sure we are not reinitializing a held lock:
4260fc2874SPeter Zijlstra */
4360fc2874SPeter Zijlstra debug_check_no_locks_freed((void *)lock, sizeof(*lock));
44de8f5e4fSPeter Zijlstra lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_CONFIG);
4560fc2874SPeter Zijlstra #endif
4660fc2874SPeter Zijlstra lock->raw_lock = (arch_rwlock_t) __ARCH_RW_LOCK_UNLOCKED;
4760fc2874SPeter Zijlstra lock->magic = RWLOCK_MAGIC;
4860fc2874SPeter Zijlstra lock->owner = SPINLOCK_OWNER_INIT;
4960fc2874SPeter Zijlstra lock->owner_cpu = -1;
5060fc2874SPeter Zijlstra }
5160fc2874SPeter Zijlstra
5260fc2874SPeter Zijlstra EXPORT_SYMBOL(__rwlock_init);
538282947fSThomas Gleixner #endif
5460fc2874SPeter Zijlstra
spin_dump(raw_spinlock_t * lock,const char * msg)5560fc2874SPeter Zijlstra static void spin_dump(raw_spinlock_t *lock, const char *msg)
5660fc2874SPeter Zijlstra {
571a365e82SMarco Elver struct task_struct *owner = READ_ONCE(lock->owner);
5860fc2874SPeter Zijlstra
591a365e82SMarco Elver if (owner == SPINLOCK_OWNER_INIT)
601a365e82SMarco Elver owner = NULL;
6160fc2874SPeter Zijlstra printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n",
6260fc2874SPeter Zijlstra msg, raw_smp_processor_id(),
6360fc2874SPeter Zijlstra current->comm, task_pid_nr(current));
6460fc2874SPeter Zijlstra printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, "
6560fc2874SPeter Zijlstra ".owner_cpu: %d\n",
661a365e82SMarco Elver lock, READ_ONCE(lock->magic),
6760fc2874SPeter Zijlstra owner ? owner->comm : "<none>",
6860fc2874SPeter Zijlstra owner ? task_pid_nr(owner) : -1,
691a365e82SMarco Elver READ_ONCE(lock->owner_cpu));
7060fc2874SPeter Zijlstra dump_stack();
7160fc2874SPeter Zijlstra }
7260fc2874SPeter Zijlstra
spin_bug(raw_spinlock_t * lock,const char * msg)7360fc2874SPeter Zijlstra static void spin_bug(raw_spinlock_t *lock, const char *msg)
7460fc2874SPeter Zijlstra {
7560fc2874SPeter Zijlstra if (!debug_locks_off())
7660fc2874SPeter Zijlstra return;
7760fc2874SPeter Zijlstra
7860fc2874SPeter Zijlstra spin_dump(lock, msg);
7960fc2874SPeter Zijlstra }
8060fc2874SPeter Zijlstra
8160fc2874SPeter Zijlstra #define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg)
8260fc2874SPeter Zijlstra
8360fc2874SPeter Zijlstra static inline void
debug_spin_lock_before(raw_spinlock_t * lock)8460fc2874SPeter Zijlstra debug_spin_lock_before(raw_spinlock_t *lock)
8560fc2874SPeter Zijlstra {
861a365e82SMarco Elver SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic");
871a365e82SMarco Elver SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion");
881a365e82SMarco Elver SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(),
8960fc2874SPeter Zijlstra lock, "cpu recursion");
9060fc2874SPeter Zijlstra }
9160fc2874SPeter Zijlstra
debug_spin_lock_after(raw_spinlock_t * lock)9260fc2874SPeter Zijlstra static inline void debug_spin_lock_after(raw_spinlock_t *lock)
9360fc2874SPeter Zijlstra {
941a365e82SMarco Elver WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
951a365e82SMarco Elver WRITE_ONCE(lock->owner, current);
9660fc2874SPeter Zijlstra }
9760fc2874SPeter Zijlstra
debug_spin_unlock(raw_spinlock_t * lock)9860fc2874SPeter Zijlstra static inline void debug_spin_unlock(raw_spinlock_t *lock)
9960fc2874SPeter Zijlstra {
10060fc2874SPeter Zijlstra SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic");
10160fc2874SPeter Zijlstra SPIN_BUG_ON(!raw_spin_is_locked(lock), lock, "already unlocked");
10260fc2874SPeter Zijlstra SPIN_BUG_ON(lock->owner != current, lock, "wrong owner");
10360fc2874SPeter Zijlstra SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
10460fc2874SPeter Zijlstra lock, "wrong CPU");
1051a365e82SMarco Elver WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
1061a365e82SMarco Elver WRITE_ONCE(lock->owner_cpu, -1);
10760fc2874SPeter Zijlstra }
10860fc2874SPeter Zijlstra
10960fc2874SPeter Zijlstra /*
110bc88c10dSWaiman Long * We are now relying on the NMI watchdog to detect lockup instead of doing
111bc88c10dSWaiman Long * the detection here with an unfair lock which can cause problem of its own.
11260fc2874SPeter Zijlstra */
do_raw_spin_lock(raw_spinlock_t * lock)11360fc2874SPeter Zijlstra void do_raw_spin_lock(raw_spinlock_t *lock)
11460fc2874SPeter Zijlstra {
11560fc2874SPeter Zijlstra debug_spin_lock_before(lock);
116bc88c10dSWaiman Long arch_spin_lock(&lock->raw_lock);
11760ca1e5aSWill Deacon mmiowb_spin_lock();
11860fc2874SPeter Zijlstra debug_spin_lock_after(lock);
11960fc2874SPeter Zijlstra }
12060fc2874SPeter Zijlstra
do_raw_spin_trylock(raw_spinlock_t * lock)12160fc2874SPeter Zijlstra int do_raw_spin_trylock(raw_spinlock_t *lock)
12260fc2874SPeter Zijlstra {
12360fc2874SPeter Zijlstra int ret = arch_spin_trylock(&lock->raw_lock);
12460fc2874SPeter Zijlstra
12560ca1e5aSWill Deacon if (ret) {
12660ca1e5aSWill Deacon mmiowb_spin_lock();
12760fc2874SPeter Zijlstra debug_spin_lock_after(lock);
12860ca1e5aSWill Deacon }
12960fc2874SPeter Zijlstra #ifndef CONFIG_SMP
13060fc2874SPeter Zijlstra /*
13160fc2874SPeter Zijlstra * Must not happen on UP:
13260fc2874SPeter Zijlstra */
13360fc2874SPeter Zijlstra SPIN_BUG_ON(!ret, lock, "trylock failure on UP");
13460fc2874SPeter Zijlstra #endif
13560fc2874SPeter Zijlstra return ret;
13660fc2874SPeter Zijlstra }
13760fc2874SPeter Zijlstra
do_raw_spin_unlock(raw_spinlock_t * lock)13860fc2874SPeter Zijlstra void do_raw_spin_unlock(raw_spinlock_t *lock)
13960fc2874SPeter Zijlstra {
14060ca1e5aSWill Deacon mmiowb_spin_unlock();
14160fc2874SPeter Zijlstra debug_spin_unlock(lock);
14260fc2874SPeter Zijlstra arch_spin_unlock(&lock->raw_lock);
14360fc2874SPeter Zijlstra }
14460fc2874SPeter Zijlstra
1458282947fSThomas Gleixner #ifndef CONFIG_PREEMPT_RT
rwlock_bug(rwlock_t * lock,const char * msg)14660fc2874SPeter Zijlstra static void rwlock_bug(rwlock_t *lock, const char *msg)
14760fc2874SPeter Zijlstra {
14860fc2874SPeter Zijlstra if (!debug_locks_off())
14960fc2874SPeter Zijlstra return;
15060fc2874SPeter Zijlstra
15160fc2874SPeter Zijlstra printk(KERN_EMERG "BUG: rwlock %s on CPU#%d, %s/%d, %p\n",
15260fc2874SPeter Zijlstra msg, raw_smp_processor_id(), current->comm,
15360fc2874SPeter Zijlstra task_pid_nr(current), lock);
15460fc2874SPeter Zijlstra dump_stack();
15560fc2874SPeter Zijlstra }
15660fc2874SPeter Zijlstra
15760fc2874SPeter Zijlstra #define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
15860fc2874SPeter Zijlstra
do_raw_read_lock(rwlock_t * lock)15960fc2874SPeter Zijlstra void do_raw_read_lock(rwlock_t *lock)
16060fc2874SPeter Zijlstra {
16160fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
16260fc2874SPeter Zijlstra arch_read_lock(&lock->raw_lock);
16360fc2874SPeter Zijlstra }
16460fc2874SPeter Zijlstra
do_raw_read_trylock(rwlock_t * lock)16560fc2874SPeter Zijlstra int do_raw_read_trylock(rwlock_t *lock)
16660fc2874SPeter Zijlstra {
16760fc2874SPeter Zijlstra int ret = arch_read_trylock(&lock->raw_lock);
16860fc2874SPeter Zijlstra
16960fc2874SPeter Zijlstra #ifndef CONFIG_SMP
17060fc2874SPeter Zijlstra /*
17160fc2874SPeter Zijlstra * Must not happen on UP:
17260fc2874SPeter Zijlstra */
17360fc2874SPeter Zijlstra RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP");
17460fc2874SPeter Zijlstra #endif
17560fc2874SPeter Zijlstra return ret;
17660fc2874SPeter Zijlstra }
17760fc2874SPeter Zijlstra
do_raw_read_unlock(rwlock_t * lock)17860fc2874SPeter Zijlstra void do_raw_read_unlock(rwlock_t *lock)
17960fc2874SPeter Zijlstra {
18060fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
18160fc2874SPeter Zijlstra arch_read_unlock(&lock->raw_lock);
18260fc2874SPeter Zijlstra }
18360fc2874SPeter Zijlstra
debug_write_lock_before(rwlock_t * lock)18460fc2874SPeter Zijlstra static inline void debug_write_lock_before(rwlock_t *lock)
18560fc2874SPeter Zijlstra {
18660fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
18760fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->owner == current, lock, "recursion");
18860fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->owner_cpu == raw_smp_processor_id(),
18960fc2874SPeter Zijlstra lock, "cpu recursion");
19060fc2874SPeter Zijlstra }
19160fc2874SPeter Zijlstra
debug_write_lock_after(rwlock_t * lock)19260fc2874SPeter Zijlstra static inline void debug_write_lock_after(rwlock_t *lock)
19360fc2874SPeter Zijlstra {
1941a365e82SMarco Elver WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id());
1951a365e82SMarco Elver WRITE_ONCE(lock->owner, current);
19660fc2874SPeter Zijlstra }
19760fc2874SPeter Zijlstra
debug_write_unlock(rwlock_t * lock)19860fc2874SPeter Zijlstra static inline void debug_write_unlock(rwlock_t *lock)
19960fc2874SPeter Zijlstra {
20060fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
20160fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner");
20260fc2874SPeter Zijlstra RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(),
20360fc2874SPeter Zijlstra lock, "wrong CPU");
2041a365e82SMarco Elver WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT);
2051a365e82SMarco Elver WRITE_ONCE(lock->owner_cpu, -1);
20660fc2874SPeter Zijlstra }
20760fc2874SPeter Zijlstra
do_raw_write_lock(rwlock_t * lock)20860fc2874SPeter Zijlstra void do_raw_write_lock(rwlock_t *lock)
20960fc2874SPeter Zijlstra {
21060fc2874SPeter Zijlstra debug_write_lock_before(lock);
21160fc2874SPeter Zijlstra arch_write_lock(&lock->raw_lock);
21260fc2874SPeter Zijlstra debug_write_lock_after(lock);
21360fc2874SPeter Zijlstra }
21460fc2874SPeter Zijlstra
do_raw_write_trylock(rwlock_t * lock)21560fc2874SPeter Zijlstra int do_raw_write_trylock(rwlock_t *lock)
21660fc2874SPeter Zijlstra {
21760fc2874SPeter Zijlstra int ret = arch_write_trylock(&lock->raw_lock);
21860fc2874SPeter Zijlstra
21960fc2874SPeter Zijlstra if (ret)
22060fc2874SPeter Zijlstra debug_write_lock_after(lock);
22160fc2874SPeter Zijlstra #ifndef CONFIG_SMP
22260fc2874SPeter Zijlstra /*
22360fc2874SPeter Zijlstra * Must not happen on UP:
22460fc2874SPeter Zijlstra */
22560fc2874SPeter Zijlstra RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP");
22660fc2874SPeter Zijlstra #endif
22760fc2874SPeter Zijlstra return ret;
22860fc2874SPeter Zijlstra }
22960fc2874SPeter Zijlstra
do_raw_write_unlock(rwlock_t * lock)23060fc2874SPeter Zijlstra void do_raw_write_unlock(rwlock_t *lock)
23160fc2874SPeter Zijlstra {
23260fc2874SPeter Zijlstra debug_write_unlock(lock);
23360fc2874SPeter Zijlstra arch_write_unlock(&lock->raw_lock);
23460fc2874SPeter Zijlstra }
2358282947fSThomas Gleixner
2368282947fSThomas Gleixner #endif /* !CONFIG_PREEMPT_RT */
237