diff options
| author | Ingo Molnar <mingo@elte.hu> | 2006-07-03 00:24:54 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 15:27:04 -0700 | 
| commit | 8a25d5debff2daee280e83e09d8c25d67c26a972 (patch) | |
| tree | 3bccfef9acb66fc62863bfd6c16493c5e8c8e394 /kernel | |
| parent | 4ea2176dfa714882e88180b474e4cbcd888b70af (diff) | |
| download | olio-linux-3.10-8a25d5debff2daee280e83e09d8c25d67c26a972.tar.xz olio-linux-3.10-8a25d5debff2daee280e83e09d8c25d67c26a972.zip  | |
[PATCH] lockdep: prove spinlock rwlock locking correctness
Use the lock validator framework to prove spinlock and rwlock locking
correctness.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 1 | ||||
| -rw-r--r-- | kernel/sched.c | 10 | ||||
| -rw-r--r-- | kernel/spinlock.c | 79 | 
3 files changed, 81 insertions, 9 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index df6ef326369..47dbcd570cd 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o  obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o  obj-$(CONFIG_SMP) += cpu.o spinlock.o  obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o +obj-$(CONFIG_PROVE_LOCKING) += spinlock.o  obj-$(CONFIG_UID16) += uid16.o  obj-$(CONFIG_MODULES) += module.o  obj-$(CONFIG_KALLSYMS) += kallsyms.o diff --git a/kernel/sched.c b/kernel/sched.c index 91182996653..ae4db0185bb 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -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 */  	rq->lock.owner = current;  #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);  } @@ -1778,6 +1785,7 @@ task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)  		WARN_ON(rq->prev_mm);  		rq->prev_mm = oldmm;  	} +	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);  	/* Here we just switch the register state and the stack. */  	switch_to(prev, next, prev); @@ -4384,6 +4392,7 @@ asmlinkage long sys_sched_yield(void)  	 * no need to preempt or enable interrupts:  	 */  	__release(rq->lock); +	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);  	_raw_spin_unlock(&rq->lock);  	preempt_enable_no_resched(); @@ -4447,6 +4456,7 @@ int cond_resched_lock(spinlock_t *lock)  		spin_lock(lock);  	}  	if (need_resched() && __resched_legal()) { +		spin_release(&lock->dep_map, 1, _THIS_IP_);  		_raw_spin_unlock(lock);  		preempt_enable_no_resched();  		__cond_resched(); diff --git a/kernel/spinlock.c b/kernel/spinlock.c index b31e54eadf5..bfd6ad9c033 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -13,6 +13,7 @@  #include <linux/preempt.h>  #include <linux/spinlock.h>  #include <linux/interrupt.h> +#include <linux/debug_locks.h>  #include <linux/module.h>  /* @@ -29,8 +30,10 @@ EXPORT_SYMBOL(generic__raw_read_trylock);  int __lockfunc _spin_trylock(spinlock_t *lock)  {  	preempt_disable(); -	if (_raw_spin_trylock(lock)) +	if (_raw_spin_trylock(lock)) { +		spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);  		return 1; +	}  	preempt_enable();  	return 0; @@ -40,8 +43,10 @@ EXPORT_SYMBOL(_spin_trylock);  int __lockfunc _read_trylock(rwlock_t *lock)  {  	preempt_disable(); -	if (_raw_read_trylock(lock)) +	if (_raw_read_trylock(lock)) { +		rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_);  		return 1; +	}  	preempt_enable();  	return 0; @@ -51,19 +56,28 @@ EXPORT_SYMBOL(_read_trylock);  int __lockfunc _write_trylock(rwlock_t *lock)  {  	preempt_disable(); -	if (_raw_write_trylock(lock)) +	if (_raw_write_trylock(lock)) { +		rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_);  		return 1; +	}  	preempt_enable();  	return 0;  }  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)  {  	preempt_disable(); +	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_read_lock(lock);  }  EXPORT_SYMBOL(_read_lock); @@ -74,7 +88,17 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)  	local_irq_save(flags);  	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); +#endif  	return flags;  }  EXPORT_SYMBOL(_spin_lock_irqsave); @@ -83,6 +107,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock)  {  	local_irq_disable();  	preempt_disable(); +	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_spin_lock(lock);  }  EXPORT_SYMBOL(_spin_lock_irq); @@ -91,6 +116,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock)  {  	local_bh_disable();  	preempt_disable(); +	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_spin_lock(lock);  }  EXPORT_SYMBOL(_spin_lock_bh); @@ -101,6 +127,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)  	local_irq_save(flags);  	preempt_disable(); +	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_read_lock(lock);  	return flags;  } @@ -110,6 +137,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock)  {  	local_irq_disable();  	preempt_disable(); +	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_read_lock(lock);  }  EXPORT_SYMBOL(_read_lock_irq); @@ -118,6 +146,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock)  {  	local_bh_disable();  	preempt_disable(); +	rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_read_lock(lock);  }  EXPORT_SYMBOL(_read_lock_bh); @@ -128,6 +157,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)  	local_irq_save(flags);  	preempt_disable(); +	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_write_lock(lock);  	return flags;  } @@ -137,6 +167,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock)  {  	local_irq_disable();  	preempt_disable(); +	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_write_lock(lock);  }  EXPORT_SYMBOL(_write_lock_irq); @@ -145,6 +176,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock)  {  	local_bh_disable();  	preempt_disable(); +	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_write_lock(lock);  }  EXPORT_SYMBOL(_write_lock_bh); @@ -152,6 +184,7 @@ EXPORT_SYMBOL(_write_lock_bh);  void __lockfunc _spin_lock(spinlock_t *lock)  {  	preempt_disable(); +	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_spin_lock(lock);  } @@ -160,6 +193,7 @@ EXPORT_SYMBOL(_spin_lock);  void __lockfunc _write_lock(rwlock_t *lock)  {  	preempt_disable(); +	rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);  	_raw_write_lock(lock);  } @@ -255,8 +289,22 @@ BUILD_LOCK_OPS(write, rwlock);  #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)  { +	spin_release(&lock->dep_map, 1, _RET_IP_);  	_raw_spin_unlock(lock);  	preempt_enable();  } @@ -264,6 +312,7 @@ EXPORT_SYMBOL(_spin_unlock);  void __lockfunc _write_unlock(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_write_unlock(lock);  	preempt_enable();  } @@ -271,6 +320,7 @@ EXPORT_SYMBOL(_write_unlock);  void __lockfunc _read_unlock(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_read_unlock(lock);  	preempt_enable();  } @@ -278,6 +328,7 @@ EXPORT_SYMBOL(_read_unlock);  void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)  { +	spin_release(&lock->dep_map, 1, _RET_IP_);  	_raw_spin_unlock(lock);  	local_irq_restore(flags);  	preempt_enable(); @@ -286,6 +337,7 @@ EXPORT_SYMBOL(_spin_unlock_irqrestore);  void __lockfunc _spin_unlock_irq(spinlock_t *lock)  { +	spin_release(&lock->dep_map, 1, _RET_IP_);  	_raw_spin_unlock(lock);  	local_irq_enable();  	preempt_enable(); @@ -294,14 +346,16 @@ EXPORT_SYMBOL(_spin_unlock_irq);  void __lockfunc _spin_unlock_bh(spinlock_t *lock)  { +	spin_release(&lock->dep_map, 1, _RET_IP_);  	_raw_spin_unlock(lock);  	preempt_enable_no_resched(); -	local_bh_enable(); +	local_bh_enable_ip((unsigned long)__builtin_return_address(0));  }  EXPORT_SYMBOL(_spin_unlock_bh);  void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_read_unlock(lock);  	local_irq_restore(flags);  	preempt_enable(); @@ -310,6 +364,7 @@ EXPORT_SYMBOL(_read_unlock_irqrestore);  void __lockfunc _read_unlock_irq(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_read_unlock(lock);  	local_irq_enable();  	preempt_enable(); @@ -318,14 +373,16 @@ EXPORT_SYMBOL(_read_unlock_irq);  void __lockfunc _read_unlock_bh(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_read_unlock(lock);  	preempt_enable_no_resched(); -	local_bh_enable(); +	local_bh_enable_ip((unsigned long)__builtin_return_address(0));  }  EXPORT_SYMBOL(_read_unlock_bh);  void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_write_unlock(lock);  	local_irq_restore(flags);  	preempt_enable(); @@ -334,6 +391,7 @@ EXPORT_SYMBOL(_write_unlock_irqrestore);  void __lockfunc _write_unlock_irq(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_write_unlock(lock);  	local_irq_enable();  	preempt_enable(); @@ -342,9 +400,10 @@ EXPORT_SYMBOL(_write_unlock_irq);  void __lockfunc _write_unlock_bh(rwlock_t *lock)  { +	rwlock_release(&lock->dep_map, 1, _RET_IP_);  	_raw_write_unlock(lock);  	preempt_enable_no_resched(); -	local_bh_enable(); +	local_bh_enable_ip((unsigned long)__builtin_return_address(0));  }  EXPORT_SYMBOL(_write_unlock_bh); @@ -352,11 +411,13 @@ int __lockfunc _spin_trylock_bh(spinlock_t *lock)  {  	local_bh_disable();  	preempt_disable(); -	if (_raw_spin_trylock(lock)) +	if (_raw_spin_trylock(lock)) { +		spin_acquire(&lock->dep_map, 0, 1, _RET_IP_);  		return 1; +	}  	preempt_enable_no_resched(); -	local_bh_enable(); +	local_bh_enable_ip((unsigned long)__builtin_return_address(0));  	return 0;  }  EXPORT_SYMBOL(_spin_trylock_bh);  |