Commit 8a25d5de authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] lockdep: prove spinlock rwlock locking correctness

Use the lock validator framework to prove spinlock and rwlock locking
correctness.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4ea2176d
...@@ -68,6 +68,12 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) ...@@ -68,6 +68,12 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
"=m" (lock->slock) : : "memory"); "=m" (lock->slock) : : "memory");
} }
/*
* It is easier for the lock validator if interrupts are not re-enabled
* in the middle of a lock-acquire. This is a performance feature anyway
* so we turn it off:
*/
#ifndef CONFIG_PROVE_LOCKING
static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
{ {
alternative_smp( alternative_smp(
...@@ -75,6 +81,7 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla ...@@ -75,6 +81,7 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla
__raw_spin_lock_string_up, __raw_spin_lock_string_up,
"=m" (lock->slock) : "r" (flags) : "memory"); "=m" (lock->slock) : "r" (flags) : "memory");
} }
#endif
static inline int __raw_spin_trylock(raw_spinlock_t *lock) static inline int __raw_spin_trylock(raw_spinlock_t *lock)
{ {
......
...@@ -82,14 +82,40 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); ...@@ -82,14 +82,40 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
/* /*
* Pull the __raw*() functions/declarations (UP-nondebug doesnt need them): * Pull the __raw*() functions/declarations (UP-nondebug doesnt need them):
*/ */
#if defined(CONFIG_SMP) #ifdef CONFIG_SMP
# include <asm/spinlock.h> # include <asm/spinlock.h>
#else #else
# include <linux/spinlock_up.h> # include <linux/spinlock_up.h>
#endif #endif
#define spin_lock_init(lock) do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) #ifdef CONFIG_DEBUG_SPINLOCK
#define rwlock_init(lock) do { *(lock) = RW_LOCK_UNLOCKED; } while (0) extern void __spin_lock_init(spinlock_t *lock, const char *name,
struct lock_class_key *key);
# define spin_lock_init(lock) \
do { \
static struct lock_class_key __key; \
\
__spin_lock_init((lock), #lock, &__key); \
} while (0)
#else
# define spin_lock_init(lock) \
do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0)
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
extern void __rwlock_init(rwlock_t *lock, const char *name,
struct lock_class_key *key);
# define rwlock_init(lock) \
do { \
static struct lock_class_key __key; \
\
__rwlock_init((lock), #lock, &__key); \
} while (0)
#else
# define rwlock_init(lock) \
do { *(lock) = RW_LOCK_UNLOCKED; } while (0)
#endif
#define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) #define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock)
...@@ -113,7 +139,6 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); ...@@ -113,7 +139,6 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
extern int _raw_spin_trylock(spinlock_t *lock); extern int _raw_spin_trylock(spinlock_t *lock);
extern void _raw_spin_unlock(spinlock_t *lock); extern void _raw_spin_unlock(spinlock_t *lock);
extern void _raw_read_lock(rwlock_t *lock); extern void _raw_read_lock(rwlock_t *lock);
extern int _raw_read_trylock(rwlock_t *lock); extern int _raw_read_trylock(rwlock_t *lock);
extern void _raw_read_unlock(rwlock_t *lock); extern void _raw_read_unlock(rwlock_t *lock);
...@@ -121,17 +146,17 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); ...@@ -121,17 +146,17 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
extern int _raw_write_trylock(rwlock_t *lock); extern int _raw_write_trylock(rwlock_t *lock);
extern void _raw_write_unlock(rwlock_t *lock); extern void _raw_write_unlock(rwlock_t *lock);
#else #else
# define _raw_spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock)
# define _raw_spin_trylock(lock) __raw_spin_trylock(&(lock)->raw_lock)
# define _raw_spin_lock(lock) __raw_spin_lock(&(lock)->raw_lock) # define _raw_spin_lock(lock) __raw_spin_lock(&(lock)->raw_lock)
# define _raw_spin_lock_flags(lock, flags) \ # define _raw_spin_lock_flags(lock, flags) \
__raw_spin_lock_flags(&(lock)->raw_lock, *(flags)) __raw_spin_lock_flags(&(lock)->raw_lock, *(flags))
# define _raw_spin_trylock(lock) __raw_spin_trylock(&(lock)->raw_lock)
# define _raw_spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock)
# define _raw_read_lock(rwlock) __raw_read_lock(&(rwlock)->raw_lock) # define _raw_read_lock(rwlock) __raw_read_lock(&(rwlock)->raw_lock)
# define _raw_write_lock(rwlock) __raw_write_lock(&(rwlock)->raw_lock)
# define _raw_read_unlock(rwlock) __raw_read_unlock(&(rwlock)->raw_lock)
# define _raw_write_unlock(rwlock) __raw_write_unlock(&(rwlock)->raw_lock)
# define _raw_read_trylock(rwlock) __raw_read_trylock(&(rwlock)->raw_lock) # define _raw_read_trylock(rwlock) __raw_read_trylock(&(rwlock)->raw_lock)
# define _raw_read_unlock(rwlock) __raw_read_unlock(&(rwlock)->raw_lock)
# define _raw_write_lock(rwlock) __raw_write_lock(&(rwlock)->raw_lock)
# define _raw_write_trylock(rwlock) __raw_write_trylock(&(rwlock)->raw_lock) # define _raw_write_trylock(rwlock) __raw_write_trylock(&(rwlock)->raw_lock)
# define _raw_write_unlock(rwlock) __raw_write_unlock(&(rwlock)->raw_lock)
#endif #endif
#define read_can_lock(rwlock) __raw_read_can_lock(&(rwlock)->raw_lock) #define read_can_lock(rwlock) __raw_read_can_lock(&(rwlock)->raw_lock)
...@@ -147,6 +172,13 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); ...@@ -147,6 +172,13 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
#define write_trylock(lock) __cond_lock(_write_trylock(lock)) #define write_trylock(lock) __cond_lock(_write_trylock(lock))
#define spin_lock(lock) _spin_lock(lock) #define spin_lock(lock) _spin_lock(lock)
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define spin_lock_nested(lock, subclass) _spin_lock_nested(lock, subclass)
#else
# define spin_lock_nested(lock, subclass) _spin_lock(lock)
#endif
#define write_lock(lock) _write_lock(lock) #define write_lock(lock) _write_lock(lock)
#define read_lock(lock) _read_lock(lock) #define read_lock(lock) _read_lock(lock)
...@@ -172,21 +204,18 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); ...@@ -172,21 +204,18 @@ extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock);
/* /*
* We inline the unlock functions in the nondebug case: * We inline the unlock functions in the nondebug case:
*/ */
#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
!defined(CONFIG_SMP)
# define spin_unlock(lock) _spin_unlock(lock) # define spin_unlock(lock) _spin_unlock(lock)
# define read_unlock(lock) _read_unlock(lock) # define read_unlock(lock) _read_unlock(lock)
# define write_unlock(lock) _write_unlock(lock) # define write_unlock(lock) _write_unlock(lock)
#else
# define spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock)
# define read_unlock(lock) __raw_read_unlock(&(lock)->raw_lock)
# define write_unlock(lock) __raw_write_unlock(&(lock)->raw_lock)
#endif
#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP)
# define spin_unlock_irq(lock) _spin_unlock_irq(lock) # define spin_unlock_irq(lock) _spin_unlock_irq(lock)
# define read_unlock_irq(lock) _read_unlock_irq(lock) # define read_unlock_irq(lock) _read_unlock_irq(lock)
# define write_unlock_irq(lock) _write_unlock_irq(lock) # define write_unlock_irq(lock) _write_unlock_irq(lock)
#else #else
# define spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock)
# define read_unlock(lock) __raw_read_unlock(&(lock)->raw_lock)
# define write_unlock(lock) __raw_write_unlock(&(lock)->raw_lock)
# define spin_unlock_irq(lock) \ # define spin_unlock_irq(lock) \
do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0) do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
# define read_unlock_irq(lock) \ # define read_unlock_irq(lock) \
......
...@@ -20,6 +20,8 @@ int in_lock_functions(unsigned long addr); ...@@ -20,6 +20,8 @@ int in_lock_functions(unsigned long addr);
#define assert_spin_locked(x) BUG_ON(!spin_is_locked(x)) #define assert_spin_locked(x) BUG_ON(!spin_is_locked(x))
void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t); void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t);
void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
__acquires(spinlock_t);
void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t); void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t);
void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t); void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t);
void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t); void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t);
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
do { local_irq_restore(flags); __UNLOCK(lock); } while (0) do { local_irq_restore(flags); __UNLOCK(lock); } while (0)
#define _spin_lock(lock) __LOCK(lock) #define _spin_lock(lock) __LOCK(lock)
#define _spin_lock_nested(lock, subclass) __LOCK(lock)
#define _read_lock(lock) __LOCK(lock) #define _read_lock(lock) __LOCK(lock)
#define _write_lock(lock) __LOCK(lock) #define _write_lock(lock) __LOCK(lock)
#define _spin_lock_bh(lock) __LOCK_BH(lock) #define _spin_lock_bh(lock) __LOCK_BH(lock)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* Released under the General Public License (GPL). * Released under the General Public License (GPL).
*/ */
#include <linux/lockdep.h>
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
# include <asm/spinlock_types.h> # include <asm/spinlock_types.h>
#else #else
...@@ -24,6 +26,9 @@ typedef struct { ...@@ -24,6 +26,9 @@ typedef struct {
unsigned int magic, owner_cpu; unsigned int magic, owner_cpu;
void *owner; void *owner;
#endif #endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} spinlock_t; } spinlock_t;
#define SPINLOCK_MAGIC 0xdead4ead #define SPINLOCK_MAGIC 0xdead4ead
...@@ -37,28 +42,47 @@ typedef struct { ...@@ -37,28 +42,47 @@ typedef struct {
unsigned int magic, owner_cpu; unsigned int magic, owner_cpu;
void *owner; void *owner;
#endif #endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} rwlock_t; } rwlock_t;
#define RWLOCK_MAGIC 0xdeaf1eed #define RWLOCK_MAGIC 0xdeaf1eed
#define SPINLOCK_OWNER_INIT ((void *)-1L) #define SPINLOCK_OWNER_INIT ((void *)-1L)
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define SPIN_DEP_MAP_INIT(lockname) .dep_map = { .name = #lockname }
#else
# define SPIN_DEP_MAP_INIT(lockname)
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define RW_DEP_MAP_INIT(lockname) .dep_map = { .name = #lockname }
#else
# define RW_DEP_MAP_INIT(lockname)
#endif
#ifdef CONFIG_DEBUG_SPINLOCK #ifdef CONFIG_DEBUG_SPINLOCK
# define __SPIN_LOCK_UNLOCKED(lockname) \ # define __SPIN_LOCK_UNLOCKED(lockname) \
(spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \
.magic = SPINLOCK_MAGIC, \ .magic = SPINLOCK_MAGIC, \
.owner = SPINLOCK_OWNER_INIT, \ .owner = SPINLOCK_OWNER_INIT, \
.owner_cpu = -1 } .owner_cpu = -1, \
SPIN_DEP_MAP_INIT(lockname) }
#define __RW_LOCK_UNLOCKED(lockname) \ #define __RW_LOCK_UNLOCKED(lockname) \
(rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \
.magic = RWLOCK_MAGIC, \ .magic = RWLOCK_MAGIC, \
.owner = SPINLOCK_OWNER_INIT, \ .owner = SPINLOCK_OWNER_INIT, \
.owner_cpu = -1 } .owner_cpu = -1, \
RW_DEP_MAP_INIT(lockname) }
#else #else
# define __SPIN_LOCK_UNLOCKED(lockname) \ # define __SPIN_LOCK_UNLOCKED(lockname) \
(spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED } (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \
SPIN_DEP_MAP_INIT(lockname) }
#define __RW_LOCK_UNLOCKED(lockname) \ #define __RW_LOCK_UNLOCKED(lockname) \
(rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED } (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \
RW_DEP_MAP_INIT(lockname) }
#endif #endif
#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init) #define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init)
......
...@@ -12,10 +12,14 @@ ...@@ -12,10 +12,14 @@
* Released under the General Public License (GPL). * Released under the General Public License (GPL).
*/ */
#ifdef CONFIG_DEBUG_SPINLOCK #if defined(CONFIG_DEBUG_SPINLOCK) || \
defined(CONFIG_DEBUG_LOCK_ALLOC)
typedef struct { typedef struct {
volatile unsigned int slock; volatile unsigned int slock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_spinlock_t; } raw_spinlock_t;
#define __RAW_SPIN_LOCK_UNLOCKED { 1 } #define __RAW_SPIN_LOCK_UNLOCKED { 1 }
...@@ -30,6 +34,9 @@ typedef struct { } raw_spinlock_t; ...@@ -30,6 +34,9 @@ typedef struct { } raw_spinlock_t;
typedef struct { typedef struct {
/* no debug version on UP */ /* no debug version on UP */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_rwlock_t; } raw_rwlock_t;
#define __RAW_RW_LOCK_UNLOCKED { } #define __RAW_RW_LOCK_UNLOCKED { }
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
*/ */
#ifdef CONFIG_DEBUG_SPINLOCK #ifdef CONFIG_DEBUG_SPINLOCK
#define __raw_spin_is_locked(x) ((x)->slock == 0) #define __raw_spin_is_locked(x) ((x)->slock == 0)
static inline void __raw_spin_lock(raw_spinlock_t *lock) static inline void __raw_spin_lock(raw_spinlock_t *lock)
......
...@@ -27,6 +27,7 @@ obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o ...@@ -27,6 +27,7 @@ obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o obj-$(CONFIG_SMP) += cpu.o spinlock.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_KALLSYMS) += kallsyms.o
......
...@@ -308,6 +308,13 @@ static inline void finish_lock_switch(runqueue_t *rq, task_t *prev) ...@@ -308,6 +308,13 @@ static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
/* this is a valid case when another task releases the spinlock */ /* this is a valid case when another task releases the spinlock */
rq->lock.owner = current; rq->lock.owner = current;
#endif #endif
/*
* If we are tracking spinlock dependencies then we have to
* fix up the runqueue lock - which gets 'carried over' from
* prev into current:
*/
spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
spin_unlock_irq(&rq->lock); spin_unlock_irq(&rq->lock);
} }
...@@ -1778,6 +1785,7 @@ task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next) ...@@ -1778,6 +1785,7 @@ task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)
WARN_ON(rq->prev_mm); WARN_ON(rq->prev_mm);
rq->prev_mm = oldmm; rq->prev_mm = oldmm;
} }
spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
/* Here we just switch the register state and the stack. */ /* Here we just switch the register state and the stack. */
switch_to(prev, next, prev); switch_to(prev, next, prev);
...@@ -4384,6 +4392,7 @@ asmlinkage long sys_sched_yield(void) ...@@ -4384,6 +4392,7 @@ asmlinkage long sys_sched_yield(void)
* no need to preempt or enable interrupts: * no need to preempt or enable interrupts:
*/ */
__release(rq->lock); __release(rq->lock);
spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
_raw_spin_unlock(&rq->lock); _raw_spin_unlock(&rq->lock);
preempt_enable_no_resched(); preempt_enable_no_resched();
...@@ -4447,6 +4456,7 @@ int cond_resched_lock(spinlock_t *lock) ...@@ -4447,6 +4456,7 @@ int cond_resched_lock(spinlock_t *lock)
spin_lock(lock); spin_lock(lock);
} }
if (need_resched() && __resched_legal()) { if (need_resched() && __resched_legal()) {
spin_release(&lock->dep_map, 1, _THIS_IP_);
_raw_spin_unlock(lock); _raw_spin_unlock(lock);
preempt_enable_no_resched(); preempt_enable_no_resched();
__cond_resched(); __cond_resched();
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/preempt.h> #include <linux/preempt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/debug_locks.h>
#include <linux/module.h> #include <linux/module.h>
/* /*
...@@ -29,8 +30,10 @@ EXPORT_SYMBOL(generic__raw_read_trylock); ...@@ -29,8 +30,10 @@ EXPORT_SYMBOL(generic__raw_read_trylock);
int __lockfunc _spin_trylock(spinlock_t *lock) int __lockfunc _spin_trylock(spinlock_t *lock)
{ {
preempt_disable(); preempt_disable();
if (_raw_spin_trylock(lock)) if (_raw_spin_trylock(lock)) {
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
return 1; return 1;
}
preempt_enable(); preempt_enable();
return 0; return 0;
...@@ -40,8 +43,10 @@ EXPORT_SYMBOL(_spin_trylock); ...@@ -40,8 +43,10 @@ EXPORT_SYMBOL(_spin_trylock);
int __lockfunc _read_trylock(rwlock_t *lock) int __lockfunc _read_trylock(rwlock_t *lock)
{ {
preempt_disable(); preempt_disable();
if (_raw_read_trylock(lock)) if (_raw_read_trylock(lock)) {
rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_);
return 1; return 1;
}
preempt_enable(); preempt_enable();
return 0; return 0;
...@@ -51,19 +56,28 @@ EXPORT_SYMBOL(_read_trylock); ...@@ -51,19 +56,28 @@ EXPORT_SYMBOL(_read_trylock);
int __lockfunc _write_trylock(rwlock_t *lock) int __lockfunc _write_trylock(rwlock_t *lock)
{ {
preempt_disable(); preempt_disable();
if (_raw_write_trylock(lock)) if (_raw_write_trylock(lock)) {
rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_);
return 1; return 1;
}
preempt_enable(); preempt_enable();
return 0; return 0;
} }
EXPORT_SYMBOL(_write_trylock); EXPORT_SYMBOL(_write_trylock);
#if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) /*
* If lockdep is enabled then we use the non-preemption spin-ops
* even on CONFIG_PREEMPT, because lockdep assumes that interrupts are
* not re-enabled during lock-acquire (which the preempt-spin-ops do):
*/
#if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \
defined(CONFIG_PROVE_LOCKING)
void __lockfunc _read_lock(rwlock_t *lock) void __lockfunc _read_lock(rwlock_t *lock)
{ {
preempt_disable(); preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
_raw_read_lock(lock); _raw_read_lock(lock);
} }
EXPORT_SYMBOL(_read_lock); EXPORT_SYMBOL(_read_lock);
...@@ -74,7 +88,17 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) ...@@ -74,7 +88,17 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
local_irq_save(flags); local_irq_save(flags);
preempt_disable(); preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* _raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_PROVE_LOCKING
_raw_spin_lock(lock);
#else
_raw_spin_lock_flags(lock, &flags); _raw_spin_lock_flags(lock, &flags);
#endif
return flags; return flags;
} }
EXPORT_SYMBOL(_spin_lock_irqsave); EXPORT_SYMBOL(_spin_lock_irqsave);
...@@ -83,6 +107,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock) ...@@ -83,6 +107,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock)
{ {
local_irq_disable(); local_irq_disable();
preempt_disable(); preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_spin_lock(lock); _raw_spin_lock(lock);
} }
EXPORT_SYMBOL(_spin_lock_irq); EXPORT_SYMBOL(_spin_lock_irq);
...@@ -91,6 +116,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock) ...@@ -91,6 +116,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock)
{ {
local_bh_disable(); local_bh_disable();
preempt_disable(); preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_spin_lock(lock); _raw_spin_lock(lock);
} }
EXPORT_SYMBOL(_spin_lock_bh); EXPORT_SYMBOL(_spin_lock_bh);
...@@ -101,6 +127,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) ...@@ -101,6 +127,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
local_irq_save(flags); local_irq_save(flags);
preempt_disable(); preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
_raw_read_lock(lock); _raw_read_lock(lock);
return flags; return flags;
} }
...@@ -110,6 +137,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock) ...@@ -110,6 +137,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock)
{ {
local_irq_disable(); local_irq_disable();
preempt_disable(); preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
_raw_read_lock(lock); _raw_read_lock(lock);
} }
EXPORT_SYMBOL(_read_lock_irq); EXPORT_SYMBOL(_read_lock_irq);
...@@ -118,6 +146,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock) ...@@ -118,6 +146,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock)
{ {
local_bh_disable(); local_bh_disable();
preempt_disable(); preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
_raw_read_lock(lock); _raw_read_lock(lock);
} }
EXPORT_SYMBOL(_read_lock_bh); EXPORT_SYMBOL(_read_lock_bh);
...@@ -128,6 +157,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) ...@@ -128,6 +157,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
local_irq_save(flags); local_irq_save(flags);
preempt_disable(); preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_write_lock(lock); _raw_write_lock(lock);
return flags; return flags;
} }
...@@ -137,6 +167,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock) ...@@ -137,6 +167,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock)
{ {
local_irq_disable(); local_irq_disable();
preempt_disable(); preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_write_lock(lock); _raw_write_lock(lock);
} }
EXPORT_SYMBOL(_write_lock_irq); EXPORT_SYMBOL(_write_lock_irq);
...@@ -145,6 +176,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock) ...@@ -145,6 +176,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock)
{ {
local_bh_disable(); local_bh_disable();
preempt_disable(); preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_write_lock(lock); _raw_write_lock(lock);
} }
EXPORT_SYMBOL(_write_lock_bh); EXPORT_SYMBOL(_write_lock_bh);
...@@ -152,6 +184,7 @@ EXPORT_SYMBOL(_write_lock_bh); ...@@ -152,6 +184,7 @@ EXPORT_SYMBOL(_write_lock_bh);
void __lockfunc _spin_lock(spinlock_t *lock) void __lockfunc _spin_lock(spinlock_t *lock)
{ {
preempt_disable(); preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_spin_lock(lock); _raw_spin_lock(lock);
} }
...@@ -160,6 +193,7 @@ EXPORT_SYMBOL(_spin_lock); ...@@ -160,6 +193,7 @@ EXPORT_SYMBOL(_spin_lock);
void __lockfunc _write_lock(rwlock_t *lock) void __lockfunc _write_lock(rwlock_t *lock)
{ {
preempt_disable(); preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
_raw_write_lock(lock); _raw_write_lock(lock);
} }
...@@ -255,8 +289,22 @@ BUILD_LOCK_OPS(write, rwlock); ...@@ -255,8 +289,22 @@ BUILD_LOCK_OPS(write, rwlock);
#endif /* CONFIG_PREEMPT */ #endif /* CONFIG_PREEMPT */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
{
preempt_disable();
spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
_raw_spin_lock(lock);
}
EXPORT_SYMBOL(_spin_lock_nested);
#endif
void __lockfunc _spin_unlock(spinlock_t *lock) void __lockfunc _spin_unlock(spinlock_t *lock)
{ {
spin_release(&lock->dep_map, 1, _RET_IP_);
_raw_spin_unlock(lock); _raw_spin_unlock(lock);
preempt_enable(); preempt_enable();
} }
...@@ -264,6 +312,7 @@ EXPORT_SYMBOL(_spin_unlock); ...@@ -264,6 +312,7 @@ EXPORT_SYMBOL(_spin_unlock);
void __lockfunc _write_unlock(rwlock_t *lock) void __lockfunc _write_unlock(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_write_unlock(lock); _raw_write_unlock(lock);
preempt_enable(); preempt_enable();
} }
...@@ -271,6 +320,7 @@ EXPORT_SYMBOL(_write_unlock); ...@@ -271,6 +320,7 @@ EXPORT_SYMBOL(_write_unlock);
void __lockfunc _read_unlock(rwlock_t *lock) void __lockfunc _read_unlock(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_read_unlock(lock); _raw_read_unlock(lock);
preempt_enable(); preempt_enable();
} }
...@@ -278,6 +328,7 @@ EXPORT_SYMBOL(_read_unlock); ...@@ -278,6 +328,7 @@ EXPORT_SYMBOL(_read_unlock);
void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
{ {
spin_release(&lock->dep_map, 1, _RET_IP_);
_raw_spin_unlock(lock); _raw_spin_unlock(lock);
local_irq_restore(flags); local_irq_restore(flags);
preempt_enable(); preempt_enable();
...@@ -286,6 +337,7 @@ EXPORT_SYMBOL(_spin_unlock_irqrestore); ...@@ -286,6 +337,7 @@ EXPORT_SYMBOL(_spin_unlock_irqrestore);
void __lockfunc _spin_unlock_irq(spinlock_t *lock) void __lockfunc _spin_unlock_irq(spinlock_t *lock)
{ {
spin_release(&lock->dep_map, 1, _RET_IP_);
_raw_spin_unlock(lock); _raw_spin_unlock(lock);
local_irq_enable(); local_irq_enable();
preempt_enable(); preempt_enable();
...@@ -294,14 +346,16 @@ EXPORT_SYMBOL(_spin_unlock_irq); ...@@ -294,14 +346,16 @@ EXPORT_SYMBOL(_spin_unlock_irq);
void __lockfunc _spin_unlock_bh(spinlock_t *lock) void __lockfunc _spin_unlock_bh(spinlock_t *lock)
{ {
spin_release(&lock->dep_map, 1, _RET_IP_);
_raw_spin_unlock(lock); _raw_spin_unlock(lock);
preempt_enable_no_resched(); preempt_enable_no_resched();
local_bh_enable(); local_bh_enable_ip((unsigned long)__builtin_return_address(0));
} }
EXPORT_SYMBOL(_spin_unlock_bh); EXPORT_SYMBOL(_spin_unlock_bh);
void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_read_unlock(lock); _raw_read_unlock(lock);
local_irq_restore(flags); local_irq_restore(flags);
preempt_enable(); preempt_enable();
...@@ -310,6 +364,7 @@ EXPORT_SYMBOL(_read_unlock_irqrestore); ...@@ -310,6 +364,7 @@ EXPORT_SYMBOL(_read_unlock_irqrestore);
void __lockfunc _read_unlock_irq(rwlock_t *lock) void __lockfunc _read_unlock_irq(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_read_unlock(lock); _raw_read_unlock(lock);
local_irq_enable(); local_irq_enable();
preempt_enable(); preempt_enable();
...@@ -318,14 +373,16 @@ EXPORT_SYMBOL(_read_unlock_irq); ...@@ -318,14 +373,16 @@ EXPORT_SYMBOL(_read_unlock_irq);
void __lockfunc _read_unlock_bh(rwlock_t *lock) void __lockfunc _read_unlock_bh(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_read_unlock(lock); _raw_read_unlock(lock);
preempt_enable_no_resched(); preempt_enable_no_resched();
local_bh_enable(); local_bh_enable_ip((unsigned long)__builtin_return_address(0));
} }
EXPORT_SYMBOL(_read_unlock_bh); EXPORT_SYMBOL(_read_unlock_bh);
void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_write_unlock(lock); _raw_write_unlock(lock);
local_irq_restore(flags); local_irq_restore(flags);
preempt_enable(); preempt_enable();
...@@ -334,6 +391,7 @@ EXPORT_SYMBOL(_write_unlock_irqrestore); ...@@ -334,6 +391,7 @@ EXPORT_SYMBOL(_write_unlock_irqrestore);
void __lockfunc _write_unlock_irq(rwlock_t *lock) void __lockfunc _write_unlock_irq(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_write_unlock(lock); _raw_write_unlock(lock);
local_irq_enable(); local_irq_enable();
preempt_enable(); preempt_enable();
...@@ -342,9 +400,10 @@ EXPORT_SYMBOL(_write_unlock_irq); ...@@ -342,9 +400,10 @@ EXPORT_SYMBOL(_write_unlock_irq);
void __lockfunc _write_unlock_bh(rwlock_t *lock) void __lockfunc _write_unlock_bh(rwlock_t *lock)
{ {
rwlock_release(&lock->dep_map, 1, _RET_IP_);
_raw_write_unlock(lock); _raw_write_unlock(lock);
preempt_enable_no_resched(); preempt_enable_no_resched();
local_bh_enable(); local_bh_enable_ip((unsigned long)__builtin_return_address(0));
} }
EXPORT_SYMBOL(_write_unlock_bh); EXPORT_SYMBOL(_write_unlock_bh);
...@@ -352,11 +411,13 @@ int __lockfunc _spin_trylock_bh(spinlock_t *lock) ...@@ -352,11 +411,13 @@ int __lockfunc _spin_trylock_bh(spinlock_t *lock)
{ {
local_bh_disable(); local_bh_disable();
preempt_disable(); preempt_disable();
if (_raw_spin_trylock(lock)) if (_raw_spin_trylock(lock)) {
spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);
return 1; return 1;
}
preempt_enable_no_resched(); preempt_enable_no_resched();
local_bh_enable(); local_bh_enable_ip((unsigned long)__builtin_return_address(0));
return 0; return 0;
} }
EXPORT_SYMBOL(_spin_trylock_bh); EXPORT_SYMBOL(_spin_trylock_bh);
......
...@@ -177,7 +177,12 @@ static inline void __lock_kernel(void) ...@@ -177,7 +177,12 @@ static inline void __lock_kernel(void)
static inline void __unlock_kernel(void) static inline void __unlock_kernel(void)
{ {
spin_unlock(&kernel_flag); /*
* the BKL is not covered by lockdep, so we open-code the
* unlocking sequence (and thus avoid the dep-chain ops):
*/
_raw_spin_unlock(&kernel_flag);
preempt_enable();
} }
/* /*
......
...@@ -12,6 +12,42 @@ ...@@ -12,6 +12,42 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
void __spin_lock_init(spinlock_t *lock, const char *name,
struct lock_class_key *key)
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
/*
* Make sure we are not reinitializing a held lock:
*/
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
lockdep_init_map(&lock->dep_map, name, key);
#endif
lock->raw_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
lock->magic = SPINLOCK_MAGIC;
lock->owner = SPINLOCK_OWNER_INIT;
lock->owner_cpu = -1;
}
EXPORT_SYMBOL(__spin_lock_init);
void __rwlock_init(rwlock_t *lock, const char *name,
struct lock_class_key *key)
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
/*
* Make sure we are not reinitializing a held lock:
*/
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
lockdep_init_map(&lock->dep_map, name, key);
#endif
lock->raw_lock = (raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED;
lock->magic = RWLOCK_MAGIC;
lock->owner = SPINLOCK_OWNER_INIT;
lock->owner_cpu = -1;
}
EXPORT_SYMBOL(__rwlock_init);
static void spin_bug(spinlock_t *lock, const char *msg) static void spin_bug(spinlock_t *lock, const char *msg)
{ {
struct task_struct *owner = NULL; struct task_struct *owner = NULL;
......
...@@ -205,7 +205,8 @@ __u8 ip_tos2prio[16] = { ...@@ -205,7 +205,8 @@ __u8 ip_tos2prio[16] = {
struct rt_hash_bucket { struct rt_hash_bucket {
struct rtable *chain; struct rtable *chain;
}; };
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
defined(CONFIG_PROVE_LOCKING)
/* /*
* Instead of using one spinlock for each rt_hash_bucket, we use a table of spinlocks * Instead of using one spinlock for each rt_hash_bucket, we use a table of spinlocks
* The size of this table is a power of two and depends on the number of CPUS. * The size of this table is a power of two and depends on the number of CPUS.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment