diff options
Diffstat (limited to 'kernel/mutex.c')
-rw-r--r-- | kernel/mutex.c | 74 |
1 files changed, 47 insertions, 27 deletions
diff --git a/kernel/mutex.c b/kernel/mutex.c index 7043db21bbce..8c71cf72a497 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/debug_locks.h> | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * In the DEBUG case we are using the "NULL fastpath" for mutexes, | 23 | * In the DEBUG case we are using the "NULL fastpath" for mutexes, |
@@ -38,13 +39,14 @@ | |||
38 | * | 39 | * |
39 | * It is not allowed to initialize an already locked mutex. | 40 | * It is not allowed to initialize an already locked mutex. |
40 | */ | 41 | */ |
41 | void fastcall __mutex_init(struct mutex *lock, const char *name) | 42 | void |
43 | __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) | ||
42 | { | 44 | { |
43 | atomic_set(&lock->count, 1); | 45 | atomic_set(&lock->count, 1); |
44 | spin_lock_init(&lock->wait_lock); | 46 | spin_lock_init(&lock->wait_lock); |
45 | INIT_LIST_HEAD(&lock->wait_list); | 47 | INIT_LIST_HEAD(&lock->wait_list); |
46 | 48 | ||
47 | debug_mutex_init(lock, name); | 49 | debug_mutex_init(lock, name, key); |
48 | } | 50 | } |
49 | 51 | ||
50 | EXPORT_SYMBOL(__mutex_init); | 52 | EXPORT_SYMBOL(__mutex_init); |
@@ -56,7 +58,7 @@ EXPORT_SYMBOL(__mutex_init); | |||
56 | * branch is predicted by the CPU as default-untaken. | 58 | * branch is predicted by the CPU as default-untaken. |
57 | */ | 59 | */ |
58 | static void fastcall noinline __sched | 60 | static void fastcall noinline __sched |
59 | __mutex_lock_slowpath(atomic_t *lock_count __IP_DECL__); | 61 | __mutex_lock_slowpath(atomic_t *lock_count); |
60 | 62 | ||
61 | /*** | 63 | /*** |
62 | * mutex_lock - acquire the mutex | 64 | * mutex_lock - acquire the mutex |
@@ -79,7 +81,7 @@ __mutex_lock_slowpath(atomic_t *lock_count __IP_DECL__); | |||
79 | * | 81 | * |
80 | * This function is similar to (but not equivalent to) down(). | 82 | * This function is similar to (but not equivalent to) down(). |
81 | */ | 83 | */ |
82 | void fastcall __sched mutex_lock(struct mutex *lock) | 84 | void inline fastcall __sched mutex_lock(struct mutex *lock) |
83 | { | 85 | { |
84 | might_sleep(); | 86 | might_sleep(); |
85 | /* | 87 | /* |
@@ -92,7 +94,7 @@ void fastcall __sched mutex_lock(struct mutex *lock) | |||
92 | EXPORT_SYMBOL(mutex_lock); | 94 | EXPORT_SYMBOL(mutex_lock); |
93 | 95 | ||
94 | static void fastcall noinline __sched | 96 | static void fastcall noinline __sched |
95 | __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__); | 97 | __mutex_unlock_slowpath(atomic_t *lock_count); |
96 | 98 | ||
97 | /*** | 99 | /*** |
98 | * mutex_unlock - release the mutex | 100 | * mutex_unlock - release the mutex |
@@ -120,18 +122,18 @@ EXPORT_SYMBOL(mutex_unlock); | |||
120 | * Lock a mutex (possibly interruptible), slowpath: | 122 | * Lock a mutex (possibly interruptible), slowpath: |
121 | */ | 123 | */ |
122 | static inline int __sched | 124 | static inline int __sched |
123 | __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) | 125 | __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass) |
124 | { | 126 | { |
125 | struct task_struct *task = current; | 127 | struct task_struct *task = current; |
126 | struct mutex_waiter waiter; | 128 | struct mutex_waiter waiter; |
127 | unsigned int old_val; | 129 | unsigned int old_val; |
128 | unsigned long flags; | 130 | unsigned long flags; |
129 | 131 | ||
130 | debug_mutex_init_waiter(&waiter); | ||
131 | |||
132 | spin_lock_mutex(&lock->wait_lock, flags); | 132 | spin_lock_mutex(&lock->wait_lock, flags); |
133 | 133 | ||
134 | debug_mutex_add_waiter(lock, &waiter, task->thread_info, ip); | 134 | debug_mutex_lock_common(lock, &waiter); |
135 | mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); | ||
136 | debug_mutex_add_waiter(lock, &waiter, task->thread_info); | ||
135 | 137 | ||
136 | /* add waiting tasks to the end of the waitqueue (FIFO): */ | 138 | /* add waiting tasks to the end of the waitqueue (FIFO): */ |
137 | list_add_tail(&waiter.list, &lock->wait_list); | 139 | list_add_tail(&waiter.list, &lock->wait_list); |
@@ -158,6 +160,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) | |||
158 | if (unlikely(state == TASK_INTERRUPTIBLE && | 160 | if (unlikely(state == TASK_INTERRUPTIBLE && |
159 | signal_pending(task))) { | 161 | signal_pending(task))) { |
160 | mutex_remove_waiter(lock, &waiter, task->thread_info); | 162 | mutex_remove_waiter(lock, &waiter, task->thread_info); |
163 | mutex_release(&lock->dep_map, 1, _RET_IP_); | ||
161 | spin_unlock_mutex(&lock->wait_lock, flags); | 164 | spin_unlock_mutex(&lock->wait_lock, flags); |
162 | 165 | ||
163 | debug_mutex_free_waiter(&waiter); | 166 | debug_mutex_free_waiter(&waiter); |
@@ -173,7 +176,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) | |||
173 | 176 | ||
174 | /* got the lock - rejoice! */ | 177 | /* got the lock - rejoice! */ |
175 | mutex_remove_waiter(lock, &waiter, task->thread_info); | 178 | mutex_remove_waiter(lock, &waiter, task->thread_info); |
176 | debug_mutex_set_owner(lock, task->thread_info __IP__); | 179 | debug_mutex_set_owner(lock, task->thread_info); |
177 | 180 | ||
178 | /* set it to 0 if there are no waiters left: */ | 181 | /* set it to 0 if there are no waiters left: */ |
179 | if (likely(list_empty(&lock->wait_list))) | 182 | if (likely(list_empty(&lock->wait_list))) |
@@ -183,32 +186,40 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) | |||
183 | 186 | ||
184 | debug_mutex_free_waiter(&waiter); | 187 | debug_mutex_free_waiter(&waiter); |
185 | 188 | ||
186 | DEBUG_WARN_ON(list_empty(&lock->held_list)); | ||
187 | DEBUG_WARN_ON(lock->owner != task->thread_info); | ||
188 | |||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void fastcall noinline __sched | 192 | static void fastcall noinline __sched |
193 | __mutex_lock_slowpath(atomic_t *lock_count __IP_DECL__) | 193 | __mutex_lock_slowpath(atomic_t *lock_count) |
194 | { | 194 | { |
195 | struct mutex *lock = container_of(lock_count, struct mutex, count); | 195 | struct mutex *lock = container_of(lock_count, struct mutex, count); |
196 | 196 | ||
197 | __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE __IP__); | 197 | __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0); |
198 | } | ||
199 | |||
200 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
201 | void __sched | ||
202 | mutex_lock_nested(struct mutex *lock, unsigned int subclass) | ||
203 | { | ||
204 | might_sleep(); | ||
205 | __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass); | ||
198 | } | 206 | } |
199 | 207 | ||
208 | EXPORT_SYMBOL_GPL(mutex_lock_nested); | ||
209 | #endif | ||
210 | |||
200 | /* | 211 | /* |
201 | * Release the lock, slowpath: | 212 | * Release the lock, slowpath: |
202 | */ | 213 | */ |
203 | static fastcall noinline void | 214 | static fastcall inline void |
204 | __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__) | 215 | __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested) |
205 | { | 216 | { |
206 | struct mutex *lock = container_of(lock_count, struct mutex, count); | 217 | struct mutex *lock = container_of(lock_count, struct mutex, count); |
207 | unsigned long flags; | 218 | unsigned long flags; |
208 | 219 | ||
209 | DEBUG_WARN_ON(lock->owner != current_thread_info()); | ||
210 | |||
211 | spin_lock_mutex(&lock->wait_lock, flags); | 220 | spin_lock_mutex(&lock->wait_lock, flags); |
221 | mutex_release(&lock->dep_map, nested, _RET_IP_); | ||
222 | debug_mutex_unlock(lock); | ||
212 | 223 | ||
213 | /* | 224 | /* |
214 | * some architectures leave the lock unlocked in the fastpath failure | 225 | * some architectures leave the lock unlocked in the fastpath failure |
@@ -218,8 +229,6 @@ __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__) | |||
218 | if (__mutex_slowpath_needs_to_unlock()) | 229 | if (__mutex_slowpath_needs_to_unlock()) |
219 | atomic_set(&lock->count, 1); | 230 | atomic_set(&lock->count, 1); |
220 | 231 | ||
221 | debug_mutex_unlock(lock); | ||
222 | |||
223 | if (!list_empty(&lock->wait_list)) { | 232 | if (!list_empty(&lock->wait_list)) { |
224 | /* get the first entry from the wait-list: */ | 233 | /* get the first entry from the wait-list: */ |
225 | struct mutex_waiter *waiter = | 234 | struct mutex_waiter *waiter = |
@@ -237,11 +246,20 @@ __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__) | |||
237 | } | 246 | } |
238 | 247 | ||
239 | /* | 248 | /* |
249 | * Release the lock, slowpath: | ||
250 | */ | ||
251 | static fastcall noinline void | ||
252 | __mutex_unlock_slowpath(atomic_t *lock_count) | ||
253 | { | ||
254 | __mutex_unlock_common_slowpath(lock_count, 1); | ||
255 | } | ||
256 | |||
257 | /* | ||
240 | * Here come the less common (and hence less performance-critical) APIs: | 258 | * Here come the less common (and hence less performance-critical) APIs: |
241 | * mutex_lock_interruptible() and mutex_trylock(). | 259 | * mutex_lock_interruptible() and mutex_trylock(). |
242 | */ | 260 | */ |
243 | static int fastcall noinline __sched | 261 | static int fastcall noinline __sched |
244 | __mutex_lock_interruptible_slowpath(atomic_t *lock_count __IP_DECL__); | 262 | __mutex_lock_interruptible_slowpath(atomic_t *lock_count); |
245 | 263 | ||
246 | /*** | 264 | /*** |
247 | * mutex_lock_interruptible - acquire the mutex, interruptable | 265 | * mutex_lock_interruptible - acquire the mutex, interruptable |
@@ -264,11 +282,11 @@ int fastcall __sched mutex_lock_interruptible(struct mutex *lock) | |||
264 | EXPORT_SYMBOL(mutex_lock_interruptible); | 282 | EXPORT_SYMBOL(mutex_lock_interruptible); |
265 | 283 | ||
266 | static int fastcall noinline __sched | 284 | static int fastcall noinline __sched |
267 | __mutex_lock_interruptible_slowpath(atomic_t *lock_count __IP_DECL__) | 285 | __mutex_lock_interruptible_slowpath(atomic_t *lock_count) |
268 | { | 286 | { |
269 | struct mutex *lock = container_of(lock_count, struct mutex, count); | 287 | struct mutex *lock = container_of(lock_count, struct mutex, count); |
270 | 288 | ||
271 | return __mutex_lock_common(lock, TASK_INTERRUPTIBLE __IP__); | 289 | return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0); |
272 | } | 290 | } |
273 | 291 | ||
274 | /* | 292 | /* |
@@ -284,8 +302,10 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count) | |||
284 | spin_lock_mutex(&lock->wait_lock, flags); | 302 | spin_lock_mutex(&lock->wait_lock, flags); |
285 | 303 | ||
286 | prev = atomic_xchg(&lock->count, -1); | 304 | prev = atomic_xchg(&lock->count, -1); |
287 | if (likely(prev == 1)) | 305 | if (likely(prev == 1)) { |
288 | debug_mutex_set_owner(lock, current_thread_info() __RET_IP__); | 306 | debug_mutex_set_owner(lock, current_thread_info()); |
307 | mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_); | ||
308 | } | ||
289 | /* Set it back to 0 if there are no waiters: */ | 309 | /* Set it back to 0 if there are no waiters: */ |
290 | if (likely(list_empty(&lock->wait_list))) | 310 | if (likely(list_empty(&lock->wait_list))) |
291 | atomic_set(&lock->count, 0); | 311 | atomic_set(&lock->count, 0); |
@@ -309,7 +329,7 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count) | |||
309 | * This function must not be used in interrupt context. The | 329 | * This function must not be used in interrupt context. The |
310 | * mutex must be released by the same task that acquired it. | 330 | * mutex must be released by the same task that acquired it. |
311 | */ | 331 | */ |
312 | int fastcall mutex_trylock(struct mutex *lock) | 332 | int fastcall __sched mutex_trylock(struct mutex *lock) |
313 | { | 333 | { |
314 | return __mutex_fastpath_trylock(&lock->count, | 334 | return __mutex_fastpath_trylock(&lock->count, |
315 | __mutex_trylock_slowpath); | 335 | __mutex_trylock_slowpath); |