diff options
Diffstat (limited to 'kernel/futex/core.c')
| -rw-r--r-- | kernel/futex/core.c | 26 | 
1 files changed, 17 insertions, 9 deletions
| diff --git a/kernel/futex/core.c b/kernel/futex/core.c index b22ef1efe751..514e4582b863 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -638,6 +638,7 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,  			      bool pi, bool pending_op)  {  	u32 uval, nval, mval; +	pid_t owner;  	int err;  	/* Futex address must be 32bit aligned */ @@ -659,6 +660,10 @@ retry:  	 * 2. A woken up waiter is killed before it can acquire the  	 *    futex in user space.  	 * +	 * In the second case, the wake up notification could be generated +	 * by the unlock path in user space after setting the futex value +	 * to zero or by the kernel after setting the OWNER_DIED bit below. +	 *  	 * In both cases the TID validation below prevents a wakeup of  	 * potential waiters which can cause these waiters to block  	 * forever. @@ -667,24 +672,27 @@ retry:  	 *  	 *	1) task->robust_list->list_op_pending != NULL  	 *	   @pending_op == true -	 *	2) User space futex value == 0 +	 *	2) The owner part of user space futex value == 0  	 *	3) Regular futex: @pi == false  	 *  	 * If these conditions are met, it is safe to attempt waking up a  	 * potential waiter without touching the user space futex value and -	 * trying to set the OWNER_DIED bit. The user space futex value is -	 * uncontended and the rest of the user space mutex state is -	 * consistent, so a woken waiter will just take over the -	 * uncontended futex. Setting the OWNER_DIED bit would create -	 * inconsistent state and malfunction of the user space owner died -	 * handling. +	 * trying to set the OWNER_DIED bit. If the futex value is zero, +	 * the rest of the user space mutex state is consistent, so a woken +	 * waiter will just take over the uncontended futex. Setting the +	 * OWNER_DIED bit would create inconsistent state and malfunction +	 * of the user space owner died handling. Otherwise, the OWNER_DIED +	 * bit is already set, and the woken waiter is expected to deal with +	 * this.  	 */ -	if (pending_op && !pi && !uval) { +	owner = uval & FUTEX_TID_MASK; + +	if (pending_op && !pi && !owner) {  		futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);  		return 0;  	} -	if ((uval & FUTEX_TID_MASK) != task_pid_vnr(curr)) +	if (owner != task_pid_vnr(curr))  		return 0;  	/* |