aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking/lockdep.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-08-01 13:25:08 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-05 03:23:59 -0400
commite7904a28f5331c21d17af638cb477c83662e3cb6 (patch)
tree4fd496dcdf41f61964125682664f57d50f3527e2 /kernel/locking/lockdep.c
parenteb58075149b7f0300ff19142e6245fe75db2a081 (diff)
locking/lockdep, sched/core: Implement a better lock pinning scheme
The problem with the existing lock pinning is that each pin is of value 1; this mean you can simply unpin if you know its pinned, without having any extra information. This scheme generates a random (16 bit) cookie for each pin and requires this same cookie to unpin. This means you have to keep the cookie in context. No objsize difference for !LOCKDEP kernels. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/locking/lockdep.c')
-rw-r--r--kernel/locking/lockdep.c71
1 files changed, 62 insertions, 9 deletions
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index ed9410936a22..d7f94f4c811d 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -45,6 +45,7 @@
45#include <linux/bitops.h> 45#include <linux/bitops.h>
46#include <linux/gfp.h> 46#include <linux/gfp.h>
47#include <linux/kmemcheck.h> 47#include <linux/kmemcheck.h>
48#include <linux/random.h>
48 49
49#include <asm/sections.h> 50#include <asm/sections.h>
50 51
@@ -3554,7 +3555,35 @@ static int __lock_is_held(struct lockdep_map *lock)
3554 return 0; 3555 return 0;
3555} 3556}
3556 3557
3557static void __lock_pin_lock(struct lockdep_map *lock) 3558static struct pin_cookie __lock_pin_lock(struct lockdep_map *lock)
3559{
3560 struct pin_cookie cookie = NIL_COOKIE;
3561 struct task_struct *curr = current;
3562 int i;
3563
3564 if (unlikely(!debug_locks))
3565 return cookie;
3566
3567 for (i = 0; i < curr->lockdep_depth; i++) {
3568 struct held_lock *hlock = curr->held_locks + i;
3569
3570 if (match_held_lock(hlock, lock)) {
3571 /*
3572 * Grab 16bits of randomness; this is sufficient to not
3573 * be guessable and still allows some pin nesting in
3574 * our u32 pin_count.
3575 */
3576 cookie.val = 1 + (prandom_u32() >> 16);
3577 hlock->pin_count += cookie.val;
3578 return cookie;
3579 }
3580 }
3581
3582 WARN(1, "pinning an unheld lock\n");
3583 return cookie;
3584}
3585
3586static void __lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
3558{ 3587{
3559 struct task_struct *curr = current; 3588 struct task_struct *curr = current;
3560 int i; 3589 int i;
@@ -3566,7 +3595,7 @@ static void __lock_pin_lock(struct lockdep_map *lock)
3566 struct held_lock *hlock = curr->held_locks + i; 3595 struct held_lock *hlock = curr->held_locks + i;
3567 3596
3568 if (match_held_lock(hlock, lock)) { 3597 if (match_held_lock(hlock, lock)) {
3569 hlock->pin_count++; 3598 hlock->pin_count += cookie.val;
3570 return; 3599 return;
3571 } 3600 }
3572 } 3601 }
@@ -3574,7 +3603,7 @@ static void __lock_pin_lock(struct lockdep_map *lock)
3574 WARN(1, "pinning an unheld lock\n"); 3603 WARN(1, "pinning an unheld lock\n");
3575} 3604}
3576 3605
3577static void __lock_unpin_lock(struct lockdep_map *lock) 3606static void __lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
3578{ 3607{
3579 struct task_struct *curr = current; 3608 struct task_struct *curr = current;
3580 int i; 3609 int i;
@@ -3589,7 +3618,11 @@ static void __lock_unpin_lock(struct lockdep_map *lock)
3589 if (WARN(!hlock->pin_count, "unpinning an unpinned lock\n")) 3618 if (WARN(!hlock->pin_count, "unpinning an unpinned lock\n"))
3590 return; 3619 return;
3591 3620
3592 hlock->pin_count--; 3621 hlock->pin_count -= cookie.val;
3622
3623 if (WARN((int)hlock->pin_count < 0, "pin count corrupted\n"))
3624 hlock->pin_count = 0;
3625
3593 return; 3626 return;
3594 } 3627 }
3595 } 3628 }
@@ -3720,24 +3753,44 @@ int lock_is_held(struct lockdep_map *lock)
3720} 3753}
3721EXPORT_SYMBOL_GPL(lock_is_held); 3754EXPORT_SYMBOL_GPL(lock_is_held);
3722 3755
3723void lock_pin_lock(struct lockdep_map *lock) 3756struct pin_cookie lock_pin_lock(struct lockdep_map *lock)
3724{ 3757{
3758 struct pin_cookie cookie = NIL_COOKIE;
3725 unsigned long flags; 3759 unsigned long flags;
3726 3760
3727 if (unlikely(current->lockdep_recursion)) 3761 if (unlikely(current->lockdep_recursion))
3728 return; 3762 return cookie;
3729 3763
3730 raw_local_irq_save(flags); 3764 raw_local_irq_save(flags);
3731 check_flags(flags); 3765 check_flags(flags);
3732 3766
3733 current->lockdep_recursion = 1; 3767 current->lockdep_recursion = 1;
3734 __lock_pin_lock(lock); 3768 cookie = __lock_pin_lock(lock);
3735 current->lockdep_recursion = 0; 3769 current->lockdep_recursion = 0;
3736 raw_local_irq_restore(flags); 3770 raw_local_irq_restore(flags);
3771
3772 return cookie;
3737} 3773}
3738EXPORT_SYMBOL_GPL(lock_pin_lock); 3774EXPORT_SYMBOL_GPL(lock_pin_lock);
3739 3775
3740void lock_unpin_lock(struct lockdep_map *lock) 3776void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
3777{
3778 unsigned long flags;
3779
3780 if (unlikely(current->lockdep_recursion))
3781 return;
3782
3783 raw_local_irq_save(flags);
3784 check_flags(flags);
3785
3786 current->lockdep_recursion = 1;
3787 __lock_repin_lock(lock, cookie);
3788 current->lockdep_recursion = 0;
3789 raw_local_irq_restore(flags);
3790}
3791EXPORT_SYMBOL_GPL(lock_repin_lock);
3792
3793void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
3741{ 3794{
3742 unsigned long flags; 3795 unsigned long flags;
3743 3796
@@ -3748,7 +3801,7 @@ void lock_unpin_lock(struct lockdep_map *lock)
3748 check_flags(flags); 3801 check_flags(flags);
3749 3802
3750 current->lockdep_recursion = 1; 3803 current->lockdep_recursion = 1;
3751 __lock_unpin_lock(lock); 3804 __lock_unpin_lock(lock, cookie);
3752 current->lockdep_recursion = 0; 3805 current->lockdep_recursion = 0;
3753 raw_local_irq_restore(flags); 3806 raw_local_irq_restore(flags);
3754} 3807}