diff options
Diffstat (limited to 'kernel/locking/rtmutex.c')
-rw-r--r-- | kernel/locking/rtmutex.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index eb7a46327798..a8a83a22bb91 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c | |||
@@ -260,27 +260,36 @@ static void rt_mutex_adjust_prio(struct task_struct *task) | |||
260 | */ | 260 | */ |
261 | int max_lock_depth = 1024; | 261 | int max_lock_depth = 1024; |
262 | 262 | ||
263 | static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p) | ||
264 | { | ||
265 | return p->pi_blocked_on ? p->pi_blocked_on->lock : NULL; | ||
266 | } | ||
267 | |||
263 | /* | 268 | /* |
264 | * Adjust the priority chain. Also used for deadlock detection. | 269 | * Adjust the priority chain. Also used for deadlock detection. |
265 | * Decreases task's usage by one - may thus free the task. | 270 | * Decreases task's usage by one - may thus free the task. |
266 | * | 271 | * |
267 | * @task: the task owning the mutex (owner) for which a chain walk is probably | 272 | * @task: the task owning the mutex (owner) for which a chain walk is |
268 | * needed | 273 | * probably needed |
269 | * @deadlock_detect: do we have to carry out deadlock detection? | 274 | * @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 | 275 | * @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 | 276 | * things for a task that has just got its priority adjusted, and |
272 | * is waiting on a mutex) | 277 | * is waiting on a mutex) |
278 | * @next_lock: the mutex on which the owner of @orig_lock was blocked before | ||
279 | * we dropped its pi_lock. Is never dereferenced, only used for | ||
280 | * comparison to detect lock chain changes. | ||
273 | * @orig_waiter: rt_mutex_waiter struct for the task that has just donated | 281 | * @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 | 282 | * 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 | 283 | * depicted above or if the top waiter is gone away and we are |
276 | * actually deboosting the owner) | 284 | * actually deboosting the owner) |
277 | * @top_task: the current top waiter | 285 | * @top_task: the current top waiter |
278 | * | 286 | * |
279 | * Returns 0 or -EDEADLK. | 287 | * Returns 0 or -EDEADLK. |
280 | */ | 288 | */ |
281 | static int rt_mutex_adjust_prio_chain(struct task_struct *task, | 289 | static int rt_mutex_adjust_prio_chain(struct task_struct *task, |
282 | int deadlock_detect, | 290 | int deadlock_detect, |
283 | struct rt_mutex *orig_lock, | 291 | struct rt_mutex *orig_lock, |
292 | struct rt_mutex *next_lock, | ||
284 | struct rt_mutex_waiter *orig_waiter, | 293 | struct rt_mutex_waiter *orig_waiter, |
285 | struct task_struct *top_task) | 294 | struct task_struct *top_task) |
286 | { | 295 | { |
@@ -339,6 +348,18 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
339 | goto out_unlock_pi; | 348 | goto out_unlock_pi; |
340 | 349 | ||
341 | /* | 350 | /* |
351 | * We dropped all locks after taking a refcount on @task, so | ||
352 | * the task might have moved on in the lock chain or even left | ||
353 | * the chain completely and blocks now on an unrelated lock or | ||
354 | * on @orig_lock. | ||
355 | * | ||
356 | * We stored the lock on which @task was blocked in @next_lock, | ||
357 | * so we can detect the chain change. | ||
358 | */ | ||
359 | if (next_lock != waiter->lock) | ||
360 | goto out_unlock_pi; | ||
361 | |||
362 | /* | ||
342 | * Drop out, when the task has no waiters. Note, | 363 | * Drop out, when the task has no waiters. Note, |
343 | * top_waiter can be NULL, when we are in the deboosting | 364 | * top_waiter can be NULL, when we are in the deboosting |
344 | * mode! | 365 | * mode! |
@@ -422,11 +443,26 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
422 | __rt_mutex_adjust_prio(task); | 443 | __rt_mutex_adjust_prio(task); |
423 | } | 444 | } |
424 | 445 | ||
446 | /* | ||
447 | * Check whether the task which owns the current lock is pi | ||
448 | * blocked itself. If yes we store a pointer to the lock for | ||
449 | * the lock chain change detection above. After we dropped | ||
450 | * task->pi_lock next_lock cannot be dereferenced anymore. | ||
451 | */ | ||
452 | next_lock = task_blocked_on_lock(task); | ||
453 | |||
425 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); | 454 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); |
426 | 455 | ||
427 | top_waiter = rt_mutex_top_waiter(lock); | 456 | top_waiter = rt_mutex_top_waiter(lock); |
428 | raw_spin_unlock(&lock->wait_lock); | 457 | raw_spin_unlock(&lock->wait_lock); |
429 | 458 | ||
459 | /* | ||
460 | * We reached the end of the lock chain. Stop right here. No | ||
461 | * point to go back just to figure that out. | ||
462 | */ | ||
463 | if (!next_lock) | ||
464 | goto out_put_task; | ||
465 | |||
430 | if (!detect_deadlock && waiter != top_waiter) | 466 | if (!detect_deadlock && waiter != top_waiter) |
431 | goto out_put_task; | 467 | goto out_put_task; |
432 | 468 | ||
@@ -536,8 +572,9 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, | |||
536 | { | 572 | { |
537 | struct task_struct *owner = rt_mutex_owner(lock); | 573 | struct task_struct *owner = rt_mutex_owner(lock); |
538 | struct rt_mutex_waiter *top_waiter = waiter; | 574 | struct rt_mutex_waiter *top_waiter = waiter; |
539 | unsigned long flags; | 575 | struct rt_mutex *next_lock; |
540 | int chain_walk = 0, res; | 576 | int chain_walk = 0, res; |
577 | unsigned long flags; | ||
541 | 578 | ||
542 | /* | 579 | /* |
543 | * Early deadlock detection. We really don't want the task to | 580 | * Early deadlock detection. We really don't want the task to |
@@ -569,20 +606,28 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, | |||
569 | if (!owner) | 606 | if (!owner) |
570 | return 0; | 607 | return 0; |
571 | 608 | ||
609 | raw_spin_lock_irqsave(&owner->pi_lock, flags); | ||
572 | if (waiter == rt_mutex_top_waiter(lock)) { | 610 | if (waiter == rt_mutex_top_waiter(lock)) { |
573 | raw_spin_lock_irqsave(&owner->pi_lock, flags); | ||
574 | rt_mutex_dequeue_pi(owner, top_waiter); | 611 | rt_mutex_dequeue_pi(owner, top_waiter); |
575 | rt_mutex_enqueue_pi(owner, waiter); | 612 | rt_mutex_enqueue_pi(owner, waiter); |
576 | 613 | ||
577 | __rt_mutex_adjust_prio(owner); | 614 | __rt_mutex_adjust_prio(owner); |
578 | if (owner->pi_blocked_on) | 615 | if (owner->pi_blocked_on) |
579 | chain_walk = 1; | 616 | chain_walk = 1; |
580 | raw_spin_unlock_irqrestore(&owner->pi_lock, flags); | 617 | } else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) { |
581 | } | ||
582 | else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) | ||
583 | chain_walk = 1; | 618 | chain_walk = 1; |
619 | } | ||
584 | 620 | ||
585 | if (!chain_walk) | 621 | /* Store the lock on which owner is blocked or NULL */ |
622 | next_lock = task_blocked_on_lock(owner); | ||
623 | |||
624 | raw_spin_unlock_irqrestore(&owner->pi_lock, flags); | ||
625 | /* | ||
626 | * Even if full deadlock detection is on, if the owner is not | ||
627 | * blocked itself, we can avoid finding this out in the chain | ||
628 | * walk. | ||
629 | */ | ||
630 | if (!chain_walk || !next_lock) | ||
586 | return 0; | 631 | return 0; |
587 | 632 | ||
588 | /* | 633 | /* |
@@ -594,8 +639,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, | |||
594 | 639 | ||
595 | raw_spin_unlock(&lock->wait_lock); | 640 | raw_spin_unlock(&lock->wait_lock); |
596 | 641 | ||
597 | res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter, | 642 | res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, |
598 | task); | 643 | next_lock, waiter, task); |
599 | 644 | ||
600 | raw_spin_lock(&lock->wait_lock); | 645 | raw_spin_lock(&lock->wait_lock); |
601 | 646 | ||
@@ -644,8 +689,8 @@ static void remove_waiter(struct rt_mutex *lock, | |||
644 | { | 689 | { |
645 | int first = (waiter == rt_mutex_top_waiter(lock)); | 690 | int first = (waiter == rt_mutex_top_waiter(lock)); |
646 | struct task_struct *owner = rt_mutex_owner(lock); | 691 | struct task_struct *owner = rt_mutex_owner(lock); |
692 | struct rt_mutex *next_lock = NULL; | ||
647 | unsigned long flags; | 693 | unsigned long flags; |
648 | int chain_walk = 0; | ||
649 | 694 | ||
650 | raw_spin_lock_irqsave(¤t->pi_lock, flags); | 695 | raw_spin_lock_irqsave(¤t->pi_lock, flags); |
651 | rt_mutex_dequeue(lock, waiter); | 696 | rt_mutex_dequeue(lock, waiter); |
@@ -669,13 +714,13 @@ static void remove_waiter(struct rt_mutex *lock, | |||
669 | } | 714 | } |
670 | __rt_mutex_adjust_prio(owner); | 715 | __rt_mutex_adjust_prio(owner); |
671 | 716 | ||
672 | if (owner->pi_blocked_on) | 717 | /* Store the lock on which owner is blocked or NULL */ |
673 | chain_walk = 1; | 718 | next_lock = task_blocked_on_lock(owner); |
674 | 719 | ||
675 | raw_spin_unlock_irqrestore(&owner->pi_lock, flags); | 720 | raw_spin_unlock_irqrestore(&owner->pi_lock, flags); |
676 | } | 721 | } |
677 | 722 | ||
678 | if (!chain_walk) | 723 | if (!next_lock) |
679 | return; | 724 | return; |
680 | 725 | ||
681 | /* gets dropped in rt_mutex_adjust_prio_chain()! */ | 726 | /* gets dropped in rt_mutex_adjust_prio_chain()! */ |
@@ -683,7 +728,7 @@ static void remove_waiter(struct rt_mutex *lock, | |||
683 | 728 | ||
684 | raw_spin_unlock(&lock->wait_lock); | 729 | raw_spin_unlock(&lock->wait_lock); |
685 | 730 | ||
686 | rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current); | 731 | rt_mutex_adjust_prio_chain(owner, 0, lock, next_lock, NULL, current); |
687 | 732 | ||
688 | raw_spin_lock(&lock->wait_lock); | 733 | raw_spin_lock(&lock->wait_lock); |
689 | } | 734 | } |
@@ -696,6 +741,7 @@ static void remove_waiter(struct rt_mutex *lock, | |||
696 | void rt_mutex_adjust_pi(struct task_struct *task) | 741 | void rt_mutex_adjust_pi(struct task_struct *task) |
697 | { | 742 | { |
698 | struct rt_mutex_waiter *waiter; | 743 | struct rt_mutex_waiter *waiter; |
744 | struct rt_mutex *next_lock; | ||
699 | unsigned long flags; | 745 | unsigned long flags; |
700 | 746 | ||
701 | raw_spin_lock_irqsave(&task->pi_lock, flags); | 747 | raw_spin_lock_irqsave(&task->pi_lock, flags); |
@@ -706,12 +752,13 @@ void rt_mutex_adjust_pi(struct task_struct *task) | |||
706 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); | 752 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); |
707 | return; | 753 | return; |
708 | } | 754 | } |
709 | 755 | next_lock = waiter->lock; | |
710 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); | 756 | raw_spin_unlock_irqrestore(&task->pi_lock, flags); |
711 | 757 | ||
712 | /* gets dropped in rt_mutex_adjust_prio_chain()! */ | 758 | /* gets dropped in rt_mutex_adjust_prio_chain()! */ |
713 | get_task_struct(task); | 759 | get_task_struct(task); |
714 | rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task); | 760 | |
761 | rt_mutex_adjust_prio_chain(task, 0, NULL, next_lock, NULL, task); | ||
715 | } | 762 | } |
716 | 763 | ||
717 | /** | 764 | /** |