Futex fix for 3.7
Linus,
please pull the latest core-urgent-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core-urgent-for-linus
Single fix for a long standing futex race when taking over a futex whose owner died. You can end up with two owners, which violates quite some rules.
Thanks,
tglx
------------------>
Thomas Gleixner (1):
futex: Handle futex_pi OWNER_DIED take over correctly
kernel/futex.c | 41 ++++++++++++++++++++++------------------- 1 files changed, 22 insertions(+), 19 deletions(-)
kernel/futex.c +22 -19
@@ -716,7 +716,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,struct futex_pi_state **ps, struct task_struct *task, int set_waiters) { - int lock_taken, ret, ownerdied = 0; + int lock_taken, ret, force_take = 0;u32 uval, newval, curval, vpid =task_pid_vnr (task); retry:
@@ -755,17 +755,15 @@ retry: newval = curval |FUTEX_WAITERS ;/* -* There are two cases, where a futex might have no owner (the -* owner TID is 0): OWNER_DIED. We take over the futex in this -* case. We also do an unconditional take over, when the owner -* of the futex died. -* -* This is safe as we are protected by the hash bucket lock ! +* Should we force take the futex? See below. */ -if (unlikely (ownerdied || !(curval &FUTEX_TID_MASK ))) { -/* Keep the OWNER_DIED bit */ +if (unlikely (force_take)) { +/* +* Keep the OWNER_DIED and the WAITERS bit and set the +* new TID value. +*/ newval = (curval & ~FUTEX_TID_MASK ) | vpid; - ownerdied =0 ; + force_take =0 ; lock_taken =1 ; }
@@ -775,7 +773,7 @@ retry: goto retry;/* -* We took the lock due to owner died take over. +* We took the lock due to forced take over. */ if (unlikely (lock_taken))return 1 ;
@@ -790,20 +788,25 @@ retry:switch (ret) {case -ESRCH :/* -* No owner found for this futex. Check if the -* OWNER_DIED bit is set to figure out whether -* this is a robust futex or not. +* We failed to find an owner for this +* futex. So we have no pi_state to block +* on. This can happen in two cases: +* +* 1) The owner died +* 2) A stale FUTEX_WAITERS bit +* +* Re-read the futex value. */ if (get_futex_value_locked (&curval, uaddr))return -EFAULT ;/* -* We simply start over in case of a robust -* futex. The code above will take the futex -* and return happy. +* If the owner died or we have a stale +* WAITERS bit the owner TID in the user space +* futex is 0. */ -if (curval &FUTEX_OWNER_DIED ) { - ownerdied =1 ; +if (!(curval &FUTEX_TID_MASK )) { + force_take =1 ; goto retry; }default :