aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking/lockdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/locking/lockdep.c')
-rw-r--r--kernel/locking/lockdep.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 2168e94715b9..6c97f67ec321 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -3808,7 +3808,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
3808 hlock->references = 2; 3808 hlock->references = 2;
3809 } 3809 }
3810 3810
3811 return 1; 3811 return 2;
3812 } 3812 }
3813 } 3813 }
3814 3814
@@ -4011,22 +4011,33 @@ out:
4011} 4011}
4012 4012
4013static int reacquire_held_locks(struct task_struct *curr, unsigned int depth, 4013static int reacquire_held_locks(struct task_struct *curr, unsigned int depth,
4014 int idx) 4014 int idx, unsigned int *merged)
4015{ 4015{
4016 struct held_lock *hlock; 4016 struct held_lock *hlock;
4017 int first_idx = idx;
4017 4018
4018 if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) 4019 if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
4019 return 0; 4020 return 0;
4020 4021
4021 for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) { 4022 for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) {
4022 if (!__lock_acquire(hlock->instance, 4023 switch (__lock_acquire(hlock->instance,
4023 hlock_class(hlock)->subclass, 4024 hlock_class(hlock)->subclass,
4024 hlock->trylock, 4025 hlock->trylock,
4025 hlock->read, hlock->check, 4026 hlock->read, hlock->check,
4026 hlock->hardirqs_off, 4027 hlock->hardirqs_off,
4027 hlock->nest_lock, hlock->acquire_ip, 4028 hlock->nest_lock, hlock->acquire_ip,
4028 hlock->references, hlock->pin_count)) 4029 hlock->references, hlock->pin_count)) {
4030 case 0:
4029 return 1; 4031 return 1;
4032 case 1:
4033 break;
4034 case 2:
4035 *merged += (idx == first_idx);
4036 break;
4037 default:
4038 WARN_ON(1);
4039 return 0;
4040 }
4030 } 4041 }
4031 return 0; 4042 return 0;
4032} 4043}
@@ -4037,9 +4048,9 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
4037 unsigned long ip) 4048 unsigned long ip)
4038{ 4049{
4039 struct task_struct *curr = current; 4050 struct task_struct *curr = current;
4051 unsigned int depth, merged = 0;
4040 struct held_lock *hlock; 4052 struct held_lock *hlock;
4041 struct lock_class *class; 4053 struct lock_class *class;
4042 unsigned int depth;
4043 int i; 4054 int i;
4044 4055
4045 if (unlikely(!debug_locks)) 4056 if (unlikely(!debug_locks))
@@ -4066,14 +4077,14 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
4066 curr->lockdep_depth = i; 4077 curr->lockdep_depth = i;
4067 curr->curr_chain_key = hlock->prev_chain_key; 4078 curr->curr_chain_key = hlock->prev_chain_key;
4068 4079
4069 if (reacquire_held_locks(curr, depth, i)) 4080 if (reacquire_held_locks(curr, depth, i, &merged))
4070 return 0; 4081 return 0;
4071 4082
4072 /* 4083 /*
4073 * I took it apart and put it back together again, except now I have 4084 * I took it apart and put it back together again, except now I have
4074 * these 'spare' parts.. where shall I put them. 4085 * these 'spare' parts.. where shall I put them.
4075 */ 4086 */
4076 if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) 4087 if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth - merged))
4077 return 0; 4088 return 0;
4078 return 1; 4089 return 1;
4079} 4090}
@@ -4081,8 +4092,8 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
4081static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip) 4092static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip)
4082{ 4093{
4083 struct task_struct *curr = current; 4094 struct task_struct *curr = current;
4095 unsigned int depth, merged = 0;
4084 struct held_lock *hlock; 4096 struct held_lock *hlock;
4085 unsigned int depth;
4086 int i; 4097 int i;
4087 4098
4088 if (unlikely(!debug_locks)) 4099 if (unlikely(!debug_locks))
@@ -4109,7 +4120,11 @@ static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip)
4109 hlock->read = 1; 4120 hlock->read = 1;
4110 hlock->acquire_ip = ip; 4121 hlock->acquire_ip = ip;
4111 4122
4112 if (reacquire_held_locks(curr, depth, i)) 4123 if (reacquire_held_locks(curr, depth, i, &merged))
4124 return 0;
4125
4126 /* Merging can't happen with unchanged classes.. */
4127 if (DEBUG_LOCKS_WARN_ON(merged))
4113 return 0; 4128 return 0;
4114 4129
4115 /* 4130 /*
@@ -4118,6 +4133,7 @@ static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip)
4118 */ 4133 */
4119 if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) 4134 if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth))
4120 return 0; 4135 return 0;
4136
4121 return 1; 4137 return 1;
4122} 4138}
4123 4139
@@ -4132,8 +4148,8 @@ static int
4132__lock_release(struct lockdep_map *lock, unsigned long ip) 4148__lock_release(struct lockdep_map *lock, unsigned long ip)
4133{ 4149{
4134 struct task_struct *curr = current; 4150 struct task_struct *curr = current;
4151 unsigned int depth, merged = 1;
4135 struct held_lock *hlock; 4152 struct held_lock *hlock;
4136 unsigned int depth;
4137 int i; 4153 int i;
4138 4154
4139 if (unlikely(!debug_locks)) 4155 if (unlikely(!debug_locks))
@@ -4192,14 +4208,15 @@ __lock_release(struct lockdep_map *lock, unsigned long ip)
4192 if (i == depth-1) 4208 if (i == depth-1)
4193 return 1; 4209 return 1;
4194 4210
4195 if (reacquire_held_locks(curr, depth, i + 1)) 4211 if (reacquire_held_locks(curr, depth, i + 1, &merged))
4196 return 0; 4212 return 0;
4197 4213
4198 /* 4214 /*
4199 * We had N bottles of beer on the wall, we drank one, but now 4215 * We had N bottles of beer on the wall, we drank one, but now
4200 * there's not N-1 bottles of beer left on the wall... 4216 * there's not N-1 bottles of beer left on the wall...
4217 * Pouring two of the bottles together is acceptable.
4201 */ 4218 */
4202 DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth-1); 4219 DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth - merged);
4203 4220
4204 /* 4221 /*
4205 * Since reacquire_held_locks() would have called check_chain_key() 4222 * Since reacquire_held_locks() would have called check_chain_key()