Commit e60cbc5ceaa518d630ab8f35a7d05cee1c752648
1 parent
bd1dbcc67c
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
futex: Split out the waiter check from lookup_pi_state()
We want to be a bit more clever in futex_lock_pi_atomic() and separate the possible states. Split out the waiter verification into a separate function. No functional change. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Darren Hart <darren@dvhart.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Davidlohr Bueso <davidlohr@hp.com> Cc: Kees Cook <kees@outflux.net> Cc: wad@chromium.org Link: http://lkml.kernel.org/r/20140611204237.180458410@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Showing 1 changed file with 71 additions and 67 deletions Side-by-side Diff
kernel/futex.c
... | ... | @@ -792,90 +792,94 @@ |
792 | 792 | * [10] There is no transient state which leaves owner and user space |
793 | 793 | * TID out of sync. |
794 | 794 | */ |
795 | -static int | |
796 | -lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |
797 | - union futex_key *key, struct futex_pi_state **ps) | |
795 | + | |
796 | +/* | |
797 | + * Validate that the existing waiter has a pi_state and sanity check | |
798 | + * the pi_state against the user space value. If correct, attach to | |
799 | + * it. | |
800 | + */ | |
801 | +static int attach_to_pi_state(u32 uval, struct futex_pi_state *pi_state, | |
802 | + struct futex_pi_state **ps) | |
798 | 803 | { |
799 | - struct futex_q *match = futex_top_waiter(hb, key); | |
800 | - struct futex_pi_state *pi_state = NULL; | |
801 | - struct task_struct *p; | |
802 | 804 | pid_t pid = uval & FUTEX_TID_MASK; |
803 | 805 | |
804 | - if (match) { | |
805 | - /* | |
806 | - * Sanity check the waiter before increasing the | |
807 | - * refcount and attaching to it. | |
808 | - */ | |
809 | - pi_state = match->pi_state; | |
810 | - /* | |
811 | - * Userspace might have messed up non-PI and PI | |
812 | - * futexes [3] | |
813 | - */ | |
814 | - if (unlikely(!pi_state)) | |
815 | - return -EINVAL; | |
806 | + /* | |
807 | + * Userspace might have messed up non-PI and PI futexes [3] | |
808 | + */ | |
809 | + if (unlikely(!pi_state)) | |
810 | + return -EINVAL; | |
816 | 811 | |
817 | - WARN_ON(!atomic_read(&pi_state->refcount)); | |
812 | + WARN_ON(!atomic_read(&pi_state->refcount)); | |
818 | 813 | |
814 | + /* | |
815 | + * Handle the owner died case: | |
816 | + */ | |
817 | + if (uval & FUTEX_OWNER_DIED) { | |
819 | 818 | /* |
820 | - * Handle the owner died case: | |
819 | + * exit_pi_state_list sets owner to NULL and wakes the | |
820 | + * topmost waiter. The task which acquires the | |
821 | + * pi_state->rt_mutex will fixup owner. | |
821 | 822 | */ |
822 | - if (uval & FUTEX_OWNER_DIED) { | |
823 | + if (!pi_state->owner) { | |
823 | 824 | /* |
824 | - * exit_pi_state_list sets owner to NULL and | |
825 | - * wakes the topmost waiter. The task which | |
826 | - * acquires the pi_state->rt_mutex will fixup | |
827 | - * owner. | |
825 | + * No pi state owner, but the user space TID | |
826 | + * is not 0. Inconsistent state. [5] | |
828 | 827 | */ |
829 | - if (!pi_state->owner) { | |
830 | - /* | |
831 | - * No pi state owner, but the user | |
832 | - * space TID is not 0. Inconsistent | |
833 | - * state. [5] | |
834 | - */ | |
835 | - if (pid) | |
836 | - return -EINVAL; | |
837 | - /* | |
838 | - * Take a ref on the state and | |
839 | - * return. [4] | |
840 | - */ | |
841 | - goto out_state; | |
842 | - } | |
843 | - | |
828 | + if (pid) | |
829 | + return -EINVAL; | |
844 | 830 | /* |
845 | - * If TID is 0, then either the dying owner | |
846 | - * has not yet executed exit_pi_state_list() | |
847 | - * or some waiter acquired the rtmutex in the | |
848 | - * pi state, but did not yet fixup the TID in | |
849 | - * user space. | |
850 | - * | |
851 | - * Take a ref on the state and return. [6] | |
831 | + * Take a ref on the state and return success. [4] | |
852 | 832 | */ |
853 | - if (!pid) | |
854 | - goto out_state; | |
855 | - } else { | |
856 | - /* | |
857 | - * If the owner died bit is not set, | |
858 | - * then the pi_state must have an | |
859 | - * owner. [7] | |
860 | - */ | |
861 | - if (!pi_state->owner) | |
862 | - return -EINVAL; | |
833 | + goto out_state; | |
863 | 834 | } |
864 | 835 | |
865 | 836 | /* |
866 | - * Bail out if user space manipulated the | |
867 | - * futex value. If pi state exists then the | |
868 | - * owner TID must be the same as the user | |
869 | - * space TID. [9/10] | |
837 | + * If TID is 0, then either the dying owner has not | |
838 | + * yet executed exit_pi_state_list() or some waiter | |
839 | + * acquired the rtmutex in the pi state, but did not | |
840 | + * yet fixup the TID in user space. | |
841 | + * | |
842 | + * Take a ref on the state and return success. [6] | |
870 | 843 | */ |
871 | - if (pid != task_pid_vnr(pi_state->owner)) | |
844 | + if (!pid) | |
845 | + goto out_state; | |
846 | + } else { | |
847 | + /* | |
848 | + * If the owner died bit is not set, then the pi_state | |
849 | + * must have an owner. [7] | |
850 | + */ | |
851 | + if (!pi_state->owner) | |
872 | 852 | return -EINVAL; |
873 | - | |
874 | - out_state: | |
875 | - atomic_inc(&pi_state->refcount); | |
876 | - *ps = pi_state; | |
877 | - return 0; | |
878 | 853 | } |
854 | + | |
855 | + /* | |
856 | + * Bail out if user space manipulated the futex value. If pi | |
857 | + * state exists then the owner TID must be the same as the | |
858 | + * user space TID. [9/10] | |
859 | + */ | |
860 | + if (pid != task_pid_vnr(pi_state->owner)) | |
861 | + return -EINVAL; | |
862 | +out_state: | |
863 | + atomic_inc(&pi_state->refcount); | |
864 | + *ps = pi_state; | |
865 | + return 0; | |
866 | +} | |
867 | + | |
868 | +static int | |
869 | +lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |
870 | + union futex_key *key, struct futex_pi_state **ps) | |
871 | +{ | |
872 | + struct futex_q *match = futex_top_waiter(hb, key); | |
873 | + struct futex_pi_state *pi_state = NULL; | |
874 | + struct task_struct *p; | |
875 | + pid_t pid = uval & FUTEX_TID_MASK; | |
876 | + | |
877 | + /* | |
878 | + * If there is a waiter on that futex, validate it and | |
879 | + * attach to the pi_state when the validation succeeds. | |
880 | + */ | |
881 | + if (match) | |
882 | + return attach_to_pi_state(uval, match->pi_state, ps); | |
879 | 883 | |
880 | 884 | /* |
881 | 885 | * We are the first waiter - try to look up the real owner and attach |