diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 3717e7b306e0..20ef219bbe9b 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -716,7 +716,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, | |||
716 | struct futex_pi_state **ps, | 716 | struct futex_pi_state **ps, |
717 | struct task_struct *task, int set_waiters) | 717 | struct task_struct *task, int set_waiters) |
718 | { | 718 | { |
719 | int lock_taken, ret, ownerdied = 0; | 719 | int lock_taken, ret, force_take = 0; |
720 | u32 uval, newval, curval, vpid = task_pid_vnr(task); | 720 | u32 uval, newval, curval, vpid = task_pid_vnr(task); |
721 | 721 | ||
722 | retry: | 722 | retry: |
@@ -755,17 +755,15 @@ retry: | |||
755 | newval = curval | FUTEX_WAITERS; | 755 | newval = curval | FUTEX_WAITERS; |
756 | 756 | ||
757 | /* | 757 | /* |
758 | * There are two cases, where a futex might have no owner (the | 758 | * Should we force take the futex? See below. |
759 | * owner TID is 0): OWNER_DIED. We take over the futex in this | ||
760 | * case. We also do an unconditional take over, when the owner | ||
761 | * of the futex died. | ||
762 | * | ||
763 | * This is safe as we are protected by the hash bucket lock ! | ||
764 | */ | 759 | */ |
765 | if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) { | 760 | if (unlikely(force_take)) { |
766 | /* Keep the OWNER_DIED bit */ | 761 | /* |
762 | * Keep the OWNER_DIED and the WAITERS bit and set the | ||
763 | * new TID value. | ||
764 | */ | ||
767 | newval = (curval & ~FUTEX_TID_MASK) | vpid; | 765 | newval = (curval & ~FUTEX_TID_MASK) | vpid; |
768 | ownerdied = 0; | 766 | force_take = 0; |
769 | lock_taken = 1; | 767 | lock_taken = 1; |
770 | } | 768 | } |
771 | 769 | ||
@@ -775,7 +773,7 @@ retry: | |||
775 | goto retry; | 773 | goto retry; |
776 | 774 | ||
777 | /* | 775 | /* |
778 | * We took the lock due to owner died take over. | 776 | * We took the lock due to forced take over. |
779 | */ | 777 | */ |
780 | if (unlikely(lock_taken)) | 778 | if (unlikely(lock_taken)) |
781 | return 1; | 779 | return 1; |
@@ -790,20 +788,25 @@ retry: | |||
790 | switch (ret) { | 788 | switch (ret) { |
791 | case -ESRCH: | 789 | case -ESRCH: |
792 | /* | 790 | /* |
793 | * No owner found for this futex. Check if the | 791 | * We failed to find an owner for this |
794 | * OWNER_DIED bit is set to figure out whether | 792 | * futex. So we have no pi_state to block |
795 | * this is a robust futex or not. | 793 | * on. This can happen in two cases: |
794 | * | ||
795 | * 1) The owner died | ||
796 | * 2) A stale FUTEX_WAITERS bit | ||
797 | * | ||
798 | * Re-read the futex value. | ||
796 | */ | 799 | */ |
797 | if (get_futex_value_locked(&curval, uaddr)) | 800 | if (get_futex_value_locked(&curval, uaddr)) |
798 | return -EFAULT; | 801 | return -EFAULT; |
799 | 802 | ||
800 | /* | 803 | /* |
801 | * We simply start over in case of a robust | 804 | * If the owner died or we have a stale |
802 | * futex. The code above will take the futex | 805 | * WAITERS bit the owner TID in the user space |
803 | * and return happy. | 806 | * futex is 0. |
804 | */ | 807 | */ |
805 | if (curval & FUTEX_OWNER_DIED) { | 808 | if (!(curval & FUTEX_TID_MASK)) { |
806 | ownerdied = 1; | 809 | force_take = 1; |
807 | goto retry; | 810 | goto retry; |
808 | } | 811 | } |
809 | default: | 812 | default: |