diff options
Diffstat (limited to 'kernel/locking/lockdep.c')
-rw-r--r-- | kernel/locking/lockdep.c | 41 |
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 | ||
4013 | static int reacquire_held_locks(struct task_struct *curr, unsigned int depth, | 4013 | static 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, | |||
4081 | static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip) | 4092 | static 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() |