mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
Merge branch 'core-futexes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'core-futexes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: futex: Detect mismatched requeue targets futex: Correct futex_wait_requeue_pi() commentary
This commit is contained in:
commit
7193bea53f
1 changed files with 30 additions and 17 deletions
|
@ -115,6 +115,9 @@ struct futex_q {
|
||||||
/* rt_waiter storage for requeue_pi: */
|
/* rt_waiter storage for requeue_pi: */
|
||||||
struct rt_mutex_waiter *rt_waiter;
|
struct rt_mutex_waiter *rt_waiter;
|
||||||
|
|
||||||
|
/* The expected requeue pi target futex key: */
|
||||||
|
union futex_key *requeue_pi_key;
|
||||||
|
|
||||||
/* Bitset for the optional bitmasked wakeup */
|
/* Bitset for the optional bitmasked wakeup */
|
||||||
u32 bitset;
|
u32 bitset;
|
||||||
};
|
};
|
||||||
|
@ -1089,6 +1092,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
|
||||||
if (!top_waiter)
|
if (!top_waiter)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Ensure we requeue to the expected futex. */
|
||||||
|
if (!match_futex(top_waiter->requeue_pi_key, key2))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in
|
* Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in
|
||||||
* the contended case or if set_waiters is 1. The pi_state is returned
|
* the contended case or if set_waiters is 1. The pi_state is returned
|
||||||
|
@ -1276,6 +1283,12 @@ retry_private:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure we requeue to the expected futex for requeue_pi. */
|
||||||
|
if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Requeue nr_requeue waiters and possibly one more in the case
|
* Requeue nr_requeue waiters and possibly one more in the case
|
||||||
* of requeue_pi if we couldn't acquire the lock atomically.
|
* of requeue_pi if we couldn't acquire the lock atomically.
|
||||||
|
@ -1751,6 +1764,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
|
||||||
q.pi_state = NULL;
|
q.pi_state = NULL;
|
||||||
q.bitset = bitset;
|
q.bitset = bitset;
|
||||||
q.rt_waiter = NULL;
|
q.rt_waiter = NULL;
|
||||||
|
q.requeue_pi_key = NULL;
|
||||||
|
|
||||||
if (abs_time) {
|
if (abs_time) {
|
||||||
to = &timeout;
|
to = &timeout;
|
||||||
|
@ -1858,6 +1872,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
|
||||||
|
|
||||||
q.pi_state = NULL;
|
q.pi_state = NULL;
|
||||||
q.rt_waiter = NULL;
|
q.rt_waiter = NULL;
|
||||||
|
q.requeue_pi_key = NULL;
|
||||||
retry:
|
retry:
|
||||||
q.key = FUTEX_KEY_INIT;
|
q.key = FUTEX_KEY_INIT;
|
||||||
ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
|
ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
|
||||||
|
@ -2118,11 +2133,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
||||||
* We call schedule in futex_wait_queue_me() when we enqueue and return there
|
* We call schedule in futex_wait_queue_me() when we enqueue and return there
|
||||||
* via the following:
|
* via the following:
|
||||||
* 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
|
* 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
|
||||||
* 2) wakeup on uaddr2 after a requeue and subsequent unlock
|
* 2) wakeup on uaddr2 after a requeue
|
||||||
* 3) signal (before or after requeue)
|
* 3) signal
|
||||||
* 4) timeout (before or after requeue)
|
* 4) timeout
|
||||||
*
|
*
|
||||||
* If 3, we setup a restart_block with futex_wait_requeue_pi() as the function.
|
* If 3, cleanup and return -ERESTARTNOINTR.
|
||||||
*
|
*
|
||||||
* If 2, we may then block on trying to take the rt_mutex and return via:
|
* If 2, we may then block on trying to take the rt_mutex and return via:
|
||||||
* 5) successful lock
|
* 5) successful lock
|
||||||
|
@ -2130,7 +2145,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
||||||
* 7) timeout
|
* 7) timeout
|
||||||
* 8) other lock acquisition failure
|
* 8) other lock acquisition failure
|
||||||
*
|
*
|
||||||
* If 6, we setup a restart_block with futex_lock_pi() as the function.
|
* If 6, return -EWOULDBLOCK (restarting the syscall would do the same).
|
||||||
*
|
*
|
||||||
* If 4 or 7, we cleanup and return with -ETIMEDOUT.
|
* If 4 or 7, we cleanup and return with -ETIMEDOUT.
|
||||||
*
|
*
|
||||||
|
@ -2169,15 +2184,16 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
|
||||||
debug_rt_mutex_init_waiter(&rt_waiter);
|
debug_rt_mutex_init_waiter(&rt_waiter);
|
||||||
rt_waiter.task = NULL;
|
rt_waiter.task = NULL;
|
||||||
|
|
||||||
q.pi_state = NULL;
|
|
||||||
q.bitset = bitset;
|
|
||||||
q.rt_waiter = &rt_waiter;
|
|
||||||
|
|
||||||
key2 = FUTEX_KEY_INIT;
|
key2 = FUTEX_KEY_INIT;
|
||||||
ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
|
ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
q.pi_state = NULL;
|
||||||
|
q.bitset = bitset;
|
||||||
|
q.rt_waiter = &rt_waiter;
|
||||||
|
q.requeue_pi_key = &key2;
|
||||||
|
|
||||||
/* Prepare to wait on uaddr. */
|
/* Prepare to wait on uaddr. */
|
||||||
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
|
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -2248,14 +2264,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
|
||||||
rt_mutex_unlock(pi_mutex);
|
rt_mutex_unlock(pi_mutex);
|
||||||
} else if (ret == -EINTR) {
|
} else if (ret == -EINTR) {
|
||||||
/*
|
/*
|
||||||
* We've already been requeued, but we have no way to
|
* We've already been requeued, but cannot restart by calling
|
||||||
* restart by calling futex_lock_pi() directly. We
|
* futex_lock_pi() directly. We could restart this syscall, but
|
||||||
* could restart the syscall, but that will look at
|
* it would detect that the user space "val" changed and return
|
||||||
* the user space value and return right away. So we
|
* -EWOULDBLOCK. Save the overhead of the restart and return
|
||||||
* drop back with EWOULDBLOCK to tell user space that
|
* -EWOULDBLOCK directly.
|
||||||
* "val" has been changed. That's the same what the
|
|
||||||
* restart of the syscall would do in
|
|
||||||
* futex_wait_setup().
|
|
||||||
*/
|
*/
|
||||||
ret = -EWOULDBLOCK;
|
ret = -EWOULDBLOCK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue