diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2014-06-21 15:32:15 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2014-06-21 15:32:15 -0400 |
| commit | fddeca638ed428d447d60fc0942a094814073cc6 (patch) | |
| tree | afc558976a9bb2c501f459864819198eb5283d43 | |
| parent | 22fdcf02f6e80d64a927f702dd9d631a927d87d4 (diff) | |
| parent | 27e35715df54cbc4f2d044f681802ae30479e7fb (diff) | |
Merge branch 'locking/urgent' into locking/core
Reason: Required to add more rtmutex robustness changes on top of
those already in mainline.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | kernel/locking/rtmutex-debug.h | 5 | ||||
| -rw-r--r-- | kernel/locking/rtmutex.c | 243 | ||||
| -rw-r--r-- | kernel/locking/rtmutex.h | 5 |
3 files changed, 218 insertions, 35 deletions
diff --git a/kernel/locking/rtmutex-debug.h b/kernel/locking/rtmutex-debug.h index 14193d596d78..ab29b6a22669 100644 --- a/kernel/locking/rtmutex-debug.h +++ b/kernel/locking/rtmutex-debug.h | |||
| @@ -31,3 +31,8 @@ static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter, | |||
| 31 | { | 31 | { |
| 32 | return (waiter != NULL); | 32 | return (waiter != NULL); |
| 33 | } | 33 | } |
| 34 | |||
| 35 | static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w) | ||
| 36 | { | ||
| 37 | debug_rt_mutex_print_deadlock(w); | ||
| 38 | } | ||
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index a620d4d08ca6..fc605941b9b8 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c | |||
| @@ -83,6 +83,47 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) | |||
| 83 | owner = *p; | 83 | owner = *p; |
| 84 | } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner); | 84 | } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner); |
| 85 | } | 85 | } |
| 86 | |||
| 87 | /* | ||
| 88 | * Safe fastpath aware unlock: | ||
| 89 | * 1) Clear the waiters bit | ||
| 90 | * 2) Drop lock->wait_lock | ||
| 91 | * 3) Try to unlock the lock with cmpxchg | ||
| 92 | */ | ||
| 93 | static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock) | ||
| 94 | __releases(lock->wait_lock) | ||
| 95 | { | ||
| 96 | struct task_struct *owner = rt_mutex_owner(lock); | ||
| 97 | |||
| 98 | clear_rt_mutex_waiters(lock); | ||
| 99 | raw_spin_unlock(&lock->wait_lock); | ||
| 100 | /* | ||
| 101 | * If a new waiter comes in between the unlock and the cmpxchg | ||
| 102 | * we have two situations: | ||
| 103 | * | ||
| 104 | * unlock(wait_lock); | ||
| 105 | * lock(wait_lock); | ||
| 106 | * cmpxchg(p, owner, 0) == owner | ||
| 107 | * mark_rt_mutex_waiters(lock); | ||
| 108 | * acquire(lock); | ||
| 109 | * or: | ||
| 110 | * | ||
| 111 | * unlock(wait_lock); | ||
| 112 | * lock(wait_lock); | ||
| 113 | * mark_rt_mutex_waiters(lock); | ||
| 114 | * | ||
| 115 | * cmpxchg(p, owner, 0) != owner | ||
| 116 | * enqueue_waiter(); | ||
| 117 | * unlock(wait_lock); | ||
| 118 | * lock(wait_lock); | ||
| 119 | * wake waiter(); | ||
| 120 | * unlock(wait_lock); | ||
| 121 | * lock(wait_lock); | ||
| 122 | * acquire(lock); | ||
| 123 | */ | ||
| 124 | return rt_mutex_cmpxchg(lock, owner, NULL); | ||
| 125 | } | ||
| 126 | |||
| 86 | #else | 127 | #else |
| 87 | # define rt_mutex_cmpxchg(l,c,n) (0) | 128 | # define rt_mutex_cmpxchg(l,c,n) (0) |
| 88 | static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) | 129 | static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) |
| @@ -90,6 +131,17 @@ static inline void mark_rt_mutex_waiters(struct rt_mutex *lock) | |||
| 90 | lock->owner = (struct task_struct *) | 131 | lock->owner = (struct task_struct *) |
| 91 | ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS); | 132 | ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS); |
| 92 | } | 133 | } |
| 134 | |||
| 135 | /* | ||
| 136 | * Simple slow path only version: lock->owner is protected by lock->wait_lock. | ||
| 137 | */ | ||
| 138 | static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock) | ||
| 139 | __releases(lock->wait_lock) | ||
| 140 | { | ||
| 141 | lock->owner = NULL; | ||
| 142 | raw_spin_unlock(&lock->wait_lock); | ||
| 143 | return true; | ||
| 144 | } | ||
| 93 | #endif | 145 | #endif |
| 94 | 146 | ||
| 95 | static inline int | 147 | static inline int |
| @@ -260,27 +312,36 @@ static void rt_mutex_adjust_prio(struct task_struct *task) | |||
| 260 | */ | 312 | */ |
| 261 | int max_lock_depth = 1024; | 313 | int max_lock_depth = 1024; |
| 262 | 314 | ||
| 315 | static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p) | ||
| 316 | { | ||
| 317 | return p->pi_blocked_on ? p->pi_blocked_on->lock : NULL; | ||
| 318 | } | ||
| 319 | |||
| 263 | /* | 320 | /* |
| 264 | * Adjust the priority chain. Also used for deadlock detection. | 321 | * Adjust the priority chain. Also used for deadlock detection. |
| 265 | * Decreases task's usage by one - may thus free the task. | 322 | * Decreases task's usage by one - may thus free the task. |
| 266 | * | 323 | * |
| 267 | * @task: the task owning the mutex (owner) for which a chain walk is probably | 324 | * @task: the task owning the mutex (owner) for which a chain walk is |
| 268 | * needed | 325 | * probably needed |
| 269 | * @deadlock_detect: do we have to carry out deadlock detection? | 326 | * @deadlock_detect: do we have to carry out deadlock detection? |
| 270 | * @orig_lock: the mutex (can be NULL if we are walking the chain to recheck | 327 | * @orig_lock: the mutex (can be NULL if we are walking the chain to recheck |
| 271 | * things for a task that has just got its priority adjusted, and | 328 | * things for a task that has just got its priority adjusted, and |
| 272 | * is waiting on a mutex) | 329 | * is waiting on a mutex) |
| 330 | * @next_lock: the mutex on which the owner of @orig_lock was blocked before | ||
| 331 | * we dropped its pi_lock. Is never dereferenced, only used for | ||
| 332 | * comparison to detect lock chain changes. | ||
| 273 | * @orig_waiter: rt_mutex_waiter struct for the task that has just donated | 333 | * @orig_waiter: rt_mutex_waiter struct for the task that has just donated |
| 274 | * its priority to the mutex owner (can be NULL in the case | 334 | * its priority to the mutex owner (can be NULL in the case |
| 275 | * depicted above or if the top waiter is gone away and we are | 335 | * depicted above or if the top waiter is gone away and we are |
| 276 | * actually deboosting the owner) | 336 | * actually deboosting the owner) |
| 277 | * @top_task: the current top waiter | 337 | * @top_task: the current top waiter |
| 278 | * | 338 | * |
| 279 | * Returns 0 or -EDEADLK. | 339 | * Returns 0 or -EDEADLK. |
| 280 | */ | 340 | */ |
| 281 | static int rt_mutex_adjust_prio_chain(struct task_struct *task, | 341 | static int rt_mutex_adjust_prio_chain(struct task_struct *task, |
| 282 | int deadlock_detect, | 342 | int deadlock_detect, |
| 283 | struct rt_mutex *orig_lock, | 343 | struct rt_mutex *orig_lock, |
| 344 | struct rt_mutex *next_lock, | ||
| 284 | struct rt_mutex_waiter *orig_waiter, | 345 | struct rt_mutex_waiter *orig_waiter, |
| 285 | struct task_struct *top_task) | 346 | struct task_struct *top_task) |
| 286 | { | 347 | { |
| @@ -314,7 +375,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 314 | } | 375 | } |
| 315 | put_task_struct(task); | 376 | put_task_struct(task); |
| 316 | 377 | ||
| 317 | return deadlock_detect ? -EDEADLK : 0; | 378 | return -EDEADLK; |
| 318 | } | 379 | } |
| 319 | retry: | 380 | retry: |
| 320 | /* | 381 | /* |
| @@ -339,6 +400,18 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 339 | goto out_unlock_pi; | 400 | goto out_unlock_pi; |
| 340 | 401 | ||
| 341 | /* | 402 | /* |
| 403 | * We dropped all locks after taking a refcount on @task, so | ||
| 404 | * the task might have moved on in the lock chain or even left | ||
| 405 | * the chain completely and blocks now on an unrelated lock or | ||
| 406 | * on @orig_lock. | ||
| 407 | * | ||
| 408 | * We stored the lock on which @task was blocked in @next_lock, | ||
| 409 | * so we can detect the chain change. | ||
| 410 | */ | ||
| 411 | if (next_lock != waiter->lock) | ||
| 412 | goto out_unlock_pi; | ||
| 413 | |||
| 414 | /* | ||
| 342 | * Drop out, when the task has no waiters. Note, | 415 | * Drop out, when the task has no waiters. Note, |
| 343 | * top_waiter can be NULL, when we are in the deboosting | 416 | * top_waiter can be NULL, when we are in the deboosting |
| 344 | * mode! | 417 | * mode! |
| @@ -377,7 +450,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 377 | if (lock == orig_lock || rt_mutex_owner(lock) == top_task) { | 450 | if (lock == orig_lock || rt_mutex_owner(lock) == top_task) { |
| 378 | debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock); | 451 | debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock); |
| 379 | raw_spin_unlock(&lock->wait_lock); | 452 | raw_spin_unlock(&lock->wait_lock); |
| 380 | ret = deadlock_detect ? -EDEADLK : 0; | 453 | ret = -EDEADLK; |
| 381 | goto out_unlock_pi; | 454 | goto out_unlock_pi; |
| 382 | } | 455 | } |
| 383 | 456 | ||
| @@ -422,11 +495,26 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 422 | __rt_mutex_adjust_prio(task); | 495 | __rt_mutex_adjust_prio(task); |
| 423 | } | 496 | } |
| 424 | 497 | ||
| 498 | /* | ||
| 499 | * Check whether the task which owns the current lock is pi | ||
| 500 | * blocked itself. If yes we store a pointer to the lock for | ||
| 501 | * the lock chain change detection above. After we dropped | ||
| 502 | * task->pi_lock next_lock cannot be dereferenced anymore. | ||
