diff options
| author | Ingo Molnar <mingo@elte.hu> | 2006-07-03 03:24:54 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 18:27:04 -0400 |
| commit | 8a25d5debff2daee280e83e09d8c25d67c26a972 (patch) | |
| tree | 3bccfef9acb66fc62863bfd6c16493c5e8c8e394 /kernel | |
| parent | 4ea2176dfa714882e88180b474e4cbcd888b70af (diff) | |
[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 df6ef32636..47dbcd570c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -27,6 +27,7 @@ obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o | |||
| 27 | obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o | 27 | obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o |
| 28 | obj-$(CONFIG_SMP) += cpu.o spinlock.o | 28 | obj-$(CONFIG_SMP) += cpu.o spinlock.o |
| 29 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o | 29 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o |
| 30 | obj-$(CONFIG_PROVE_LOCKING) += spinlock.o | ||
| 30 | obj-$(CONFIG_UID16) += uid16.o | 31 | obj-$(CONFIG_UID16) += uid16.o |
| 31 | obj-$(CONFIG_MODULES) += module.o | 32 | obj-$(CONFIG_MODULES) += module.o |
| 32 | obj-$(CONFIG_KALLSYMS) += kallsyms.o | 33 | obj-$(CONFIG_KALLSYMS) += kallsyms.o |
diff --git a/kernel/sched.c b/kernel/sched.c index 9118299665..ae4db0185b 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) | |||
| 308 | /* this is a valid case when another task releases the spinlock */ | 308 | /* this is a valid case when another task releases the spinlock */ |
| 309 | rq->lock.owner = current; | 309 | rq->lock.owner = current; |
| 310 | #endif | 310 | #endif |
| 311 | /* | ||
| 312 | * If we are tracking spinlock dependencies then we have to | ||
| 313 | * fix up the runqueue lock - which gets 'carried over' from | ||
| 314 | * prev into current: | ||
| 315 | */ | ||
| 316 | spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_); | ||
| 317 | |||
| 311 | spin_unlock_irq(&rq->lock); | 318 | spin_unlock_irq(&rq->lock); |
| 312 | } | 319 | } |
| 313 | 320 | ||
| @@ -1778,6 +1785,7 @@ task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next) | |||
| 1778 | WARN_ON(rq->prev_mm); | 1785 | WARN_ON(rq->prev_mm); |
| 1779 | rq->prev_mm = oldmm; | 1786 | rq->prev_mm = oldmm; |
| 1780 | } | 1787 | } |
| 1788 | spin_release(&rq->lock.dep_map, 1, _THIS_IP_); | ||
| 1781 | 1789 | ||
| 1782 | /* Here we just switch the register state and the stack. */ | 1790 | /* Here we just switch the register state and the stack. */ |
| 1783 | switch_to(prev, next, prev); | 1791 | switch_to(prev, next, prev); |
| @@ -4384,6 +4392,7 @@ asmlinkage long sys_sched_yield(void) | |||
| 4384 | * no need to preempt or enable interrupts: | 4392 | * no need to preempt or enable interrupts: |
| 4385 | */ | 4393 | */ |
| 4386 | __release(rq->lock); | 4394 | __release(rq->lock); |
| 4395 | spin_release(&rq->lock.dep_map, 1, _THIS_IP_); | ||
| 4387 | _raw_spin_unlock(&rq->lock); | 4396 | _raw_spin_unlock(&rq->lock); |
| 4388 | preempt_enable_no_resched(); | 4397 | preempt_enable_no_resched(); |
| 4389 | 4398 | ||
| @@ -4447,6 +4456,7 @@ int cond_resched_lock(spinlock_t *lock) | |||
| 4447 | spin_lock(lock); | 4456 | spin_lock(lock); |
| 4448 | } | 4457 | } |
| 4449 | if (need_resched() && __resched_legal()) { | 4458 | if (need_resched() && __resched_legal()) { |
| 4459 | spin_release(&lock->dep_map, 1, _THIS_IP_); | ||
| 4450 | _raw_spin_unlock(lock); | 4460 | _raw_spin_unlock(lock); |
| 4451 | preempt_enable_no_resched(); | 4461 | preempt_enable_no_resched(); |
| 4452 | __cond_resched(); | 4462 | __cond_resched(); |
diff --git a/kernel/spinlock.c b/kernel/spinlock.c index b31e54eadf..bfd6ad9c03 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/preempt.h> | 13 | #include <linux/preempt.h> |
| 14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 16 | #include <linux/debug_locks.h> | ||
| 16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 17 | 18 | ||
| 18 | /* | 19 | /* |
| @@ -29,8 +30,10 @@ EXPORT_SYMBOL(generic__raw_read_trylock); | |||
| 29 | int __lockfunc _spin_trylock(spinlock_t *lock) | 30 | int __lockfunc _spin_trylock(spinlock_t *lock) |
| 30 | { | 31 | { |
| 31 | preempt_disable(); | 32 | preempt_disable(); |
| 32 | if (_raw_spin_trylock(lock)) | 33 | if (_raw_spin_trylock(lock)) { |
| 34 | spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); | ||
| 33 | return 1; | 35 | return 1; |
| 36 | } | ||
| 34 | 37 | ||
| 35 | preempt_enable(); | 38 | preempt_enable(); |
| 36 | return 0; | 39 | return 0; |
| @@ -40,8 +43,10 @@ EXPORT_SYMBOL(_spin_trylock); | |||
| 40 | int __lockfunc _read_trylock(rwlock_t *lock) | 43 | int __lockfunc _read_trylock(rwlock_t *lock) |
| 41 | { | 44 | { |
| 42 | preempt_disable(); | 45 | preempt_disable(); |
| 43 | if (_raw_read_trylock(lock)) | 46 | if (_raw_read_trylock(lock)) { |
| 47 | rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_); | ||
| 44 | return 1; | 48 | return 1; |
| 49 | } | ||
| 45 | 50 | ||
| 46 | preempt_enable(); | 51 | preempt_enable(); |
| 47 | return 0; | 52 | return 0; |
| @@ -51,19 +56,28 @@ EXPORT_SYMBOL(_read_trylock); | |||
| 51 | int __lockfunc _write_trylock(rwlock_t *lock) | 56 | int __lockfunc _write_trylock(rwlock_t *lock) |
| 52 | { | 57 | { |
| 53 | preempt_disable(); | 58 | preempt_disable(); |
| 54 | if (_raw_write_trylock(lock)) | 59 | if (_raw_write_trylock(lock)) { |
| 60 | rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_); | ||
| 55 | return 1; | 61 | return 1; |
| 62 | } | ||
| 56 | 63 | ||
| 57 | preempt_enable(); | 64 | preempt_enable(); |
| 58 | return 0; | 65 | return 0; |
| 59 | } | 66 | } |
| 60 | EXPORT_SYMBOL(_write_trylock); | 67 | EXPORT_SYMBOL(_write_trylock); |
| 61 | 68 | ||
| 62 | #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) | 69 | /* |
| 70 | * If lockdep is enabled then we use the non-preemption spin-ops | ||
| 71 | * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are | ||
| 72 | * not re-enabled during lock-acquire (which the preempt-spin-ops do): | ||
| 73 | */ | ||
| 74 | #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \ | ||
| 75 | defined(CONFIG_PROVE_LOCKING) | ||
| 63 | 76 | ||
| 64 | void __lockfunc _read_lock(rwlock_t *lock) | 77 | void __lockfunc _read_lock(rwlock_t *lock) |
| 65 | { | 78 | { |
| 66 | preempt_disable(); | 79 | preempt_disable(); |
| 80 | rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 67 | _raw_read_lock(lock); | 81 | _raw_read_lock(lock); |
| 68 | } | 82 | } |
| 69 | EXPORT_SYMBOL(_read_lock); | 83 | EXPORT_SYMBOL(_read_lock); |
| @@ -74,7 +88,17 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) | |||
| 74 | 88 | ||
| 75 | local_irq_save(flags); | 89 | local_irq_save(flags); |
| 76 | preempt_disable(); | 90 | preempt_disable(); |
| 91 | spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 92 | /* | ||
| 93 | * On lockdep we dont want the hand-coded irq-enable of | ||
| 94 | * _raw_spin_lock_flags() code, because lockdep assumes | ||
| 95 | * that interrupts are not re-enabled during lock-acquire: | ||
| 96 | */ | ||
| 97 | #ifdef CONFIG_PROVE_LOCKING | ||
| 98 | _raw_spin_lock(lock); | ||
| 99 | #else | ||
| 77 | _raw_spin_lock_flags(lock, &flags); | 100 | _raw_spin_lock_flags(lock, &flags); |
| 101 | #endif | ||
| 78 | return flags; | 102 | return flags; |
| 79 | } | 103 | } |
| 80 | EXPORT_SYMBOL(_spin_lock_irqsave); | 104 | EXPORT_SYMBOL(_spin_lock_irqsave); |
| @@ -83,6 +107,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock) | |||
| 83 | { | 107 | { |
| 84 | local_irq_disable(); | 108 | local_irq_disable(); |
| 85 | preempt_disable(); | 109 | preempt_disable(); |
| 110 | spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 86 | _raw_spin_lock(lock); | 111 | _raw_spin_lock(lock); |
| 87 | } | 112 | } |
| 88 | EXPORT_SYMBOL(_spin_lock_irq); | 113 | EXPORT_SYMBOL(_spin_lock_irq); |
| @@ -91,6 +116,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock) | |||
| 91 | { | 116 | { |
| 92 | local_bh_disable(); | 117 | local_bh_disable(); |
| 93 | preempt_disable(); | 118 | preempt_disable(); |
| 119 | spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 94 | _raw_spin_lock(lock); | 120 | _raw_spin_lock(lock); |
| 95 | } | 121 | } |
| 96 | EXPORT_SYMBOL(_spin_lock_bh); | 122 | EXPORT_SYMBOL(_spin_lock_bh); |
| @@ -101,6 +127,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) | |||
| 101 | 127 | ||
| 102 | local_irq_save(flags); | 128 | local_irq_save(flags); |
| 103 | preempt_disable(); | 129 | preempt_disable(); |
| 130 | rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 104 | _raw_read_lock(lock); | 131 | _raw_read_lock(lock); |
| 105 | return flags; | 132 | return flags; |
| 106 | } | 133 | } |
| @@ -110,6 +137,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock) | |||
| 110 | { | 137 | { |
| 111 | local_irq_disable(); | 138 | local_irq_disable(); |
| 112 | preempt_disable(); | 139 | preempt_disable(); |
| 140 | rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 113 | _raw_read_lock(lock); | 141 | _raw_read_lock(lock); |
| 114 | } | 142 | } |
| 115 | EXPORT_SYMBOL(_read_lock_irq); | 143 | EXPORT_SYMBOL(_read_lock_irq); |
| @@ -118,6 +146,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock) | |||
| 118 | { | 146 | { |
| 119 | local_bh_disable(); | 147 | local_bh_disable(); |
| 120 | preempt_disable(); | 148 | preempt_disable(); |
| 149 | rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 121 | _raw_read_lock(lock); | 150 | _raw_read_lock(lock); |
| 122 | } | 151 | } |
| 123 | EXPORT_SYMBOL(_read_lock_bh); | 152 | EXPORT_SYMBOL(_read_lock_bh); |
| @@ -128,6 +157,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) | |||
| 128 | 157 | ||
| 129 | local_irq_save(flags); | 158 | local_irq_save(flags); |
| 130 | preempt_disable(); | 159 | preempt_disable(); |
| 160 | rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); | ||
| 131 | _raw_write_lock(lock); | 161 | _raw_write_lock(lock); |
| 132 | return flags; | 162 | return flags; |
