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); |
