Commit f3b0cfa9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-futexes-for-linus' of...

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: Add futex_q static initializer
  futex: Replace fshared and clockrt with combined flags
  futex: Cleanup stale fshared flag interfaces
parents 2af49b60 5bdb05f9
...@@ -68,6 +68,14 @@ int __read_mostly futex_cmpxchg_enabled; ...@@ -68,6 +68,14 @@ int __read_mostly futex_cmpxchg_enabled;
#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
/*
* Futex flags used to encode options to functions and preserve them across
* restarts.
*/
#define FLAGS_SHARED 0x01
#define FLAGS_CLOCKRT 0x02
#define FLAGS_HAS_TIMEOUT 0x04
/* /*
* Priority Inheritance state: * Priority Inheritance state:
*/ */
...@@ -123,6 +131,12 @@ struct futex_q { ...@@ -123,6 +131,12 @@ struct futex_q {
u32 bitset; u32 bitset;
}; };
static const struct futex_q futex_q_init = {
/* list gets initialized in queue_me()*/
.key = FUTEX_KEY_INIT,
.bitset = FUTEX_BITSET_MATCH_ANY
};
/* /*
* Hash buckets are shared by all the futex_keys that hash to the same * Hash buckets are shared by all the futex_keys that hash to the same
* location. Each key may have multiple futex_q structures, one for each task * location. Each key may have multiple futex_q structures, one for each task
...@@ -283,8 +297,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) ...@@ -283,8 +297,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
return 0; return 0;
} }
static inline static inline void put_futex_key(union futex_key *key)
void put_futex_key(int fshared, union futex_key *key)
{ {
drop_futex_key_refs(key); drop_futex_key_refs(key);
} }
...@@ -870,7 +883,8 @@ double_unlock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2) ...@@ -870,7 +883,8 @@ double_unlock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
/* /*
* Wake up waiters matching bitset queued on this futex (uaddr). * Wake up waiters matching bitset queued on this futex (uaddr).
*/ */
static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) static int
futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
{ {
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q *this, *next; struct futex_q *this, *next;
...@@ -881,7 +895,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) ...@@ -881,7 +895,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
if (!bitset) if (!bitset)
return -EINVAL; return -EINVAL;
ret = get_futex_key(uaddr, fshared, &key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -907,7 +921,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) ...@@ -907,7 +921,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
} }
spin_unlock(&hb->lock); spin_unlock(&hb->lock);
put_futex_key(fshared, &key); put_futex_key(&key);
out: out:
return ret; return ret;
} }
...@@ -917,7 +931,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) ...@@ -917,7 +931,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
* to this virtual address: * to this virtual address:
*/ */
static int static int
futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
int nr_wake, int nr_wake2, int op) int nr_wake, int nr_wake2, int op)
{ {
union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT; union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
...@@ -927,10 +941,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -927,10 +941,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
int ret, op_ret; int ret, op_ret;
retry: retry:
ret = get_futex_key(uaddr1, fshared, &key1); ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
ret = get_futex_key(uaddr2, fshared, &key2); ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_put_key1; goto out_put_key1;
...@@ -962,11 +976,11 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -962,11 +976,11 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
if (ret) if (ret)
goto out_put_keys; goto out_put_keys;
if (!fshared) if (!(flags & FLAGS_SHARED))
goto retry_private; goto retry_private;
put_futex_key(fshared, &key2); put_futex_key(&key2);
put_futex_key(fshared, &key1); put_futex_key(&key1);
goto retry; goto retry;
} }
...@@ -996,9 +1010,9 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -996,9 +1010,9 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
double_unlock_hb(hb1, hb2); double_unlock_hb(hb1, hb2);
out_put_keys: out_put_keys:
put_futex_key(fshared, &key2); put_futex_key(&key2);
out_put_key1: out_put_key1:
put_futex_key(fshared, &key1); put_futex_key(&key1);
out: out:
return ret; return ret;
} }
...@@ -1133,13 +1147,13 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, ...@@ -1133,13 +1147,13 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
/** /**
* futex_requeue() - Requeue waiters from uaddr1 to uaddr2 * futex_requeue() - Requeue waiters from uaddr1 to uaddr2
* @uaddr1: source futex user address * @uaddr1: source futex user address
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED * @flags: futex flags (FLAGS_SHARED, etc.)
* @uaddr2: target futex user address * @uaddr2: target futex user address
* @nr_wake: number of waiters to wake (must be 1 for requeue_pi) * @nr_wake: number of waiters to wake (must be 1 for requeue_pi)
* @nr_requeue: number of waiters to requeue (0-INT_MAX) * @nr_requeue: number of waiters to requeue (0-INT_MAX)
* @cmpval: @uaddr1 expected value (or %NULL) * @cmpval: @uaddr1 expected value (or %NULL)
* @requeue_pi: if we are attempting to requeue from a non-pi futex to a * @requeue_pi: if we are attempting to requeue from a non-pi futex to a
* pi futex (pi to pi requeue is not supported) * pi futex (pi to pi requeue is not supported)
* *
* Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire * Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire
* uaddr2 atomically on behalf of the top waiter. * uaddr2 atomically on behalf of the top waiter.
...@@ -1148,9 +1162,9 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, ...@@ -1148,9 +1162,9 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
* >=0 - on success, the number of tasks requeued or woken * >=0 - on success, the number of tasks requeued or woken
* <0 - on error * <0 - on error
*/ */
static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
int nr_wake, int nr_requeue, u32 *cmpval, u32 __user *uaddr2, int nr_wake, int nr_requeue,
int requeue_pi) u32 *cmpval, int requeue_pi)
{ {
union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT; union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
int drop_count = 0, task_count = 0, ret; int drop_count = 0, task_count = 0, ret;
...@@ -1191,10 +1205,10 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1191,10 +1205,10 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
pi_state = NULL; pi_state = NULL;
} }
ret = get_futex_key(uaddr1, fshared, &key1); ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
ret = get_futex_key(uaddr2, fshared, &key2); ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_put_key1; goto out_put_key1;
...@@ -1216,11 +1230,11 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1216,11 +1230,11 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
if (ret) if (ret)
goto out_put_keys; goto out_put_keys;
if (!fshared) if (!(flags & FLAGS_SHARED))
goto retry_private; goto retry_private;
put_futex_key(fshared, &key2); put_futex_key(&key2);
put_futex_key(fshared, &key1); put_futex_key(&key1);
goto retry; goto retry;
} }
if (curval != *cmpval) { if (curval != *cmpval) {
...@@ -1260,8 +1274,8 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1260,8 +1274,8 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
break; break;
case -EFAULT: case -EFAULT:
double_unlock_hb(hb1, hb2); double_unlock_hb(hb1, hb2);
put_futex_key(fshared, &key2); put_futex_key(&key2);
put_futex_key(fshared, &key1); put_futex_key(&key1);
ret = fault_in_user_writeable(uaddr2); ret = fault_in_user_writeable(uaddr2);
if (!ret) if (!ret)
goto retry; goto retry;
...@@ -1269,8 +1283,8 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1269,8 +1283,8 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
case -EAGAIN: case -EAGAIN:
/* The owner was exiting, try again. */ /* The owner was exiting, try again. */
double_unlock_hb(hb1, hb2); double_unlock_hb(hb1, hb2);
put_futex_key(fshared, &key2); put_futex_key(&key2);
put_futex_key(fshared, &key1); put_futex_key(&key1);
cond_resched(); cond_resched();
goto retry; goto retry;
default: default:
...@@ -1352,9 +1366,9 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, ...@@ -1352,9 +1366,9 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
drop_futex_key_refs(&key1); drop_futex_key_refs(&key1);
out_put_keys: out_put_keys:
put_futex_key(fshared, &key2); put_futex_key(&key2);
out_put_key1: out_put_key1:
put_futex_key(fshared, &key1); put_futex_key(&key1);
out: out:
if (pi_state != NULL) if (pi_state != NULL)
free_pi_state(pi_state); free_pi_state(pi_state);
...@@ -1494,7 +1508,7 @@ static void unqueue_me_pi(struct futex_q *q) ...@@ -1494,7 +1508,7 @@ static void unqueue_me_pi(struct futex_q *q)
* private futexes. * private futexes.
*/ */
static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
struct task_struct *newowner, int fshared) struct task_struct *newowner)
{ {
u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS; u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
struct futex_pi_state *pi_state = q->pi_state; struct futex_pi_state *pi_state = q->pi_state;
...@@ -1587,20 +1601,11 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, ...@@ -1587,20 +1601,11 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
goto retry; goto retry;
} }
/*
* In case we must use restart_block to restart a futex_wait,
* we encode in the 'flags' shared capability
*/
#define FLAGS_SHARED 0x01
#define FLAGS_CLOCKRT 0x02
#define FLAGS_HAS_TIMEOUT 0x04
static long futex_wait_restart(struct restart_block *restart); static long futex_wait_restart(struct restart_block *restart);
/** /**
* fixup_owner() - Post lock pi_state and corner case management * fixup_owner() - Post lock pi_state and corner case management
* @uaddr: user address of the futex * @uaddr: user address of the futex
* @fshared: whether the futex is shared (1) or not (0)
* @q: futex_q (contains pi_state and access to the rt_mutex) * @q: futex_q (contains pi_state and access to the rt_mutex)
* @locked: if the attempt to take the rt_mutex succeeded (1) or not (0) * @locked: if the attempt to take the rt_mutex succeeded (1) or not (0)
* *
...@@ -1613,8 +1618,7 @@ static long futex_wait_restart(struct restart_block *restart); ...@@ -1613,8 +1618,7 @@ static long futex_wait_restart(struct restart_block *restart);
* 0 - success, lock not taken * 0 - success, lock not taken
* <0 - on error (-EFAULT) * <0 - on error (-EFAULT)
*/ */
static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q, static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
int locked)
{ {
struct task_struct *owner; struct task_struct *owner;
int ret = 0; int ret = 0;
...@@ -1625,7 +1629,7 @@ static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q, ...@@ -1625,7 +1629,7 @@ static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q,
* did a lock-steal - fix up the PI-state in that case: * did a lock-steal - fix up the PI-state in that case:
*/ */
if (q->pi_state->owner != current) if (q->pi_state->owner != current)
ret = fixup_pi_state_owner(uaddr, q, current, fshared); ret = fixup_pi_state_owner(uaddr, q, current);
goto out; goto out;
} }
...@@ -1652,7 +1656,7 @@ static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q, ...@@ -1652,7 +1656,7 @@ static int fixup_owner(u32 __user *uaddr, int fshared, struct futex_q *q,
* lock. Fix the state up. * lock. Fix the state up.
*/ */
owner = rt_mutex_owner(&q->pi_state->pi_mutex); owner = rt_mutex_owner(&q->pi_state->pi_mutex);
ret = fixup_pi_state_owner(uaddr, q, owner, fshared); ret = fixup_pi_state_owner(uaddr, q, owner);
goto out; goto out;
} }
...@@ -1715,7 +1719,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, ...@@ -1715,7 +1719,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
* futex_wait_setup() - Prepare to wait on a futex * futex_wait_setup() - Prepare to wait on a futex
* @uaddr: the futex userspace address * @uaddr: the futex userspace address
* @val: the expected value * @val: the expected value
* @fshared: whether the futex is shared (1) or not (0) * @flags: futex flags (FLAGS_SHARED, etc.)
* @q: the associated futex_q * @q: the associated futex_q
* @hb: storage for hash_bucket pointer to be returned to caller * @hb: storage for hash_bucket pointer to be returned to caller
* *
...@@ -1728,7 +1732,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, ...@@ -1728,7 +1732,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
* 0 - uaddr contains val and hb has been locked * 0 - uaddr contains val and hb has been locked
* <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlcoked * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlcoked
*/ */
static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
struct futex_q *q, struct futex_hash_bucket **hb) struct futex_q *q, struct futex_hash_bucket **hb)
{ {
u32 uval; u32 uval;
...@@ -1752,8 +1756,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, ...@@ -1752,8 +1756,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
* rare, but normal. * rare, but normal.
*/ */
retry: retry:
q->key = FUTEX_KEY_INIT; ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key);
ret = get_futex_key(uaddr, fshared, &q->key);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
return ret; return ret;
...@@ -1769,10 +1772,10 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, ...@@ -1769,10 +1772,10 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
if (ret) if (ret)
goto out; goto out;
if (!fshared) if (!(flags & FLAGS_SHARED))
goto retry_private; goto retry_private;
put_futex_key(fshared, &q->key); put_futex_key(&q->key);
goto retry; goto retry;
} }
...@@ -1783,32 +1786,29 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, ...@@ -1783,32 +1786,29 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
out: out:
if (ret) if (ret)
put_futex_key(fshared, &q->key); put_futex_key(&q->key);
return ret; return ret;
} }
static int futex_wait(u32 __user *uaddr, int fshared, static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
u32 val, ktime_t *abs_time, u32 bitset, int clockrt) ktime_t *abs_time, u32 bitset)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to = NULL;
struct restart_block *restart; struct restart_block *restart;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q q; struct futex_q q = futex_q_init;
int ret; int ret;
if (!bitset) if (!bitset)
return -EINVAL; return -EINVAL;
q.pi_state = NULL;
q.bitset = bitset; q.bitset = bitset;
q.rt_waiter = NULL;
q.requeue_pi_key = NULL;
if (abs_time) { if (abs_time) {
to = &timeout; to = &timeout;
hrtimer_init_on_stack(&to->timer, clockrt ? CLOCK_REALTIME : hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
CLOCK_MONOTONIC, HRTIMER_MODE_ABS); CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current); hrtimer_init_sleeper(to, current);
hrtimer_set_expires_range_ns(&to->timer, *abs_time, hrtimer_set_expires_range_ns(&to->timer, *abs_time,
current->timer_slack_ns); current->timer_slack_ns);
...@@ -1819,7 +1819,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, ...@@ -1819,7 +1819,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
* Prepare to wait on uaddr. On success, holds hb lock and increments * Prepare to wait on uaddr. On success, holds hb lock and increments
* q.key refs. * q.key refs.
*/ */
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
if (ret) if (ret)
goto out; goto out;
...@@ -1852,12 +1852,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, ...@@ -1852,12 +1852,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
restart->futex.val = val; restart->futex.val = val;
restart->futex.time = abs_time->tv64; restart->futex.time = abs_time->tv64;
restart->futex.bitset = bitset; restart->futex.bitset = bitset;
restart->futex.flags = FLAGS_HAS_TIMEOUT; restart->futex.flags = flags;
if (fshared)
restart->futex.flags |= FLAGS_SHARED;
if (clockrt)
restart->futex.flags |= FLAGS_CLOCKRT;
ret = -ERESTART_RESTARTBLOCK; ret = -ERESTART_RESTARTBLOCK;
...@@ -1873,7 +1868,6 @@ static int futex_wait(u32 __user *uaddr, int fshared, ...@@ -1873,7 +1868,6 @@ static int futex_wait(u32 __user *uaddr, int fshared,
static long futex_wait_restart(struct restart_block *restart) static long futex_wait_restart(struct restart_block *restart)
{ {
u32 __user *uaddr = restart->futex.uaddr; u32 __user *uaddr = restart->futex.uaddr;
int fshared = 0;
ktime_t t, *tp = NULL; ktime_t t, *tp = NULL;
if (restart->futex.flags & FLAGS_HAS_TIMEOUT) { if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
...@@ -1881,11 +1875,9 @@ static long futex_wait_restart(struct restart_block *restart) ...@@ -1881,11 +1875,9 @@ static long futex_wait_restart(struct restart_block *restart)
tp = &t; tp = &t;
} }
restart->fn = do_no_restart_syscall; restart->fn = do_no_restart_syscall;
if (restart->futex.flags & FLAGS_SHARED)
fshared = 1; return (long)futex_wait(uaddr, restart->futex.flags,
return (long)futex_wait(uaddr, fshared, restart->futex.val, tp, restart->futex.val, tp, restart->futex.bitset);
restart->futex.bitset,
restart->futex.flags & FLAGS_CLOCKRT);
} }
...@@ -1895,12 +1887,12 @@ static long futex_wait_restart(struct restart_block *restart) ...@@ -1895,12 +1887,12 @@ static long futex_wait_restart(struct restart_block *restart)
* if there are waiters then it will block, it does PI, etc. (Due to * if there are waiters then it will block, it does PI, etc. (Due to
* races the kernel might see a 0 value of the futex too.) * races the kernel might see a 0 value of the futex too.)
*/ */
static int futex_lock_pi(u32 __user *uaddr, int fshared, static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect,
int detect, ktime_t *time, int trylock) ktime_t *time, int trylock)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to = NULL;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q q; struct futex_q q = futex_q_init;
int res, ret; int res, ret;
if (refill_pi_state_cache()) if (refill_pi_state_cache())
...@@ -1914,12 +1906,8 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -1914,12 +1906,8 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
hrtimer_set_expires(&to->timer, *time); hrtimer_set_expires(&to->timer, *time);
} }
q.pi_state = NULL;
q.rt_waiter = NULL;
q.requeue_pi_key = NULL;
retry: retry:
q.key = FUTEX_KEY_INIT; ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key);
ret = get_futex_key(uaddr, fshared, &q.key);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -1941,7 +1929,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -1941,7 +1929,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
* exit to complete. * exit to complete.
*/ */
queue_unlock(&q, hb); queue_unlock(&q, hb);
put_futex_key(fshared, &q.key); put_futex_key(&q.key);
cond_resched(); cond_resched();
goto retry; goto retry;
default: default:
...@@ -1971,7 +1959,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -1971,7 +1959,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
* Fixup the pi_state owner and possibly acquire the lock if we * Fixup the pi_state owner and possibly acquire the lock if we
* haven't already. * haven't already.
*/ */
res = fixup_owner(uaddr, fshared, &q, !ret); res = fixup_owner(uaddr, &q, !ret);
/* /*
* If fixup_owner() returned an error, proprogate that. If it acquired * If fixup_owner() returned an error, proprogate that. If it acquired
* the lock, clear our -ETIMEDOUT or -EINTR. * the lock, clear our -ETIMEDOUT or -EINTR.
...@@ -1995,7 +1983,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -1995,7 +1983,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
queue_unlock(&q, hb); queue_unlock(&q, hb);
out_put_key: out_put_key:
put_futex_key(fshared, &q.key); put_futex_key(&q.key);
out: out:
if (to) if (to)
destroy_hrtimer_on_stack(&to->timer); destroy_hrtimer_on_stack(&to->timer);
...@@ -2008,10 +1996,10 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -2008,10 +1996,10 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
if (ret) if (ret)
goto out_put_key; goto out_put_key;
if (!fshared) if (!(flags & FLAGS_SHARED))
goto retry_private; goto retry_private;
put_futex_key(fshared, &q.key); put_futex_key(&q.key);
goto retry; goto retry;
} }
...@@ -2020,7 +2008,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, ...@@ -2020,7 +2008,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
* This is the in-kernel slowpath: we look up the PI state (if any), * This is the in-kernel slowpath: we look up the PI state (if any),
* and do the rt-mutex unlock. * and do the rt-mutex unlock.
*/ */
static int futex_unlock_pi(u32 __user *uaddr, int fshared) static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
{ {
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
struct futex_q *this, *next; struct futex_q *this, *next;
...@@ -2038,7 +2026,7 @@ static int futex_unlock_pi(u32 __user *uaddr, int fshared) ...@@ -2038,7 +2026,7 @@ static int futex_unlock_pi(u32 __user *uaddr, int fshared)
if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current)) if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current))
return -EPERM; return -EPERM;
ret = get_futex_key(uaddr, fshared, &key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -2093,14 +2081,14 @@ static int futex_unlock_pi(u32 __user *uaddr, int fshared) ...@@ -2093,14 +2081,14 @@ static int futex_unlock_pi(u32 __user *uaddr, int fshared)
out_unlock: out_unlock:
spin_unlock(&hb->lock); spin_unlock(&hb->lock);
put_futex_key(fshared, &key); put_futex_key(&key);
out: out:
return ret; return ret;
pi_faulted: pi_faulted:
spin_unlock(&hb->lock); spin_unlock(&hb->lock);
put_futex_key(fshared, &key); put_futex_key(&key);
ret = fault_in_user_writeable(uaddr); ret = fault_in_user_writeable(uaddr);
if (!ret) if (!ret)
...@@ -2160,7 +2148,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, ...@@ -2160,7 +2148,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
/** /**
* futex_wait_requeue_pi() - Wait on uaddr and take uaddr2 * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2
* @uaddr: the futex we initially wait on (non-pi) * @uaddr: the futex we initially wait on (non-pi)
* @fshared: whether the futexes are shared (1) or not (0). They must be * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be
* the same type, no requeueing from private to shared, etc. * the same type, no requeueing from private to shared, etc.
* @val: the expected value of uaddr * @val: the expected value of uaddr
* @abs_time: absolute timeout * @abs_time: absolute timeout
...@@ -2198,16 +2186,16 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, ...@@ -2198,16 +2186,16 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
* 0 - On success * 0 - On success
* <0 - On error * <0 - On error
*/ */
static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
u32 val, ktime_t *abs_time, u32 bitset, u32 val, ktime_t *abs_time, u32 bitset,
int clockrt, u32 __user *uaddr2) u32 __user *uaddr2)
{ {
struct hrtimer_sleeper timeout, *to = NULL; struct hrtimer_sleeper timeout, *to = NULL;
struct rt_mutex_waiter rt_waiter; struct rt_mutex_waiter rt_waiter;
struct rt_mutex *pi_mutex = NULL; struct rt_mutex *pi_mutex = NULL;
struct futex_hash_bucket *hb; struct futex_hash_bucket *hb;
union futex_key key2; union futex_key key2 = FUTEX_KEY_INIT;
struct futex_q q; struct futex_q q = futex_q_init;
int res, ret; int res, ret;
if (!bitset) if (!bitset)
...@@ -2215,8 +2203,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2215,8 +2203,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
if (abs_time) { if (abs_time) {
to = &timeout; to = &timeout;
hrtimer_init_on_stack(&to->timer, clockrt ? CLOCK_REALTIME : hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
CLOCK_MONOTONIC, HRTIMER_MODE_ABS); CLOCK_REALTIME : CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current); hrtimer_init_sleeper(to, current);
hrtimer_set_expires_range_ns(&to->timer, *abs_time, hrtimer_set_expires_range_ns(&to->timer, *abs_time,
current->timer_slack_ns); current->timer_slack_ns);
...@@ -2229,12 +2218,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2229,12 +2218,10 @@ 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;
key2 = FUTEX_KEY_INIT; ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2);
ret = get_futex_key(uaddr2, fshared, &key2);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
q.pi_state = NULL;
q.bitset = bitset; q.bitset = bitset;
q.rt_waiter = &rt_waiter; q.rt_waiter = &rt_waiter;
q.requeue_pi_key = &key2; q.requeue_pi_key = &key2;
...@@ -2243,7 +2230,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2243,7 +2230,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
* Prepare to wait on uaddr. On success, increments q.key (key1) ref * Prepare to wait on uaddr. On success, increments q.key (key1) ref
* count. * count.
*/ */
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
if (ret) if (ret)
goto out_key2; goto out_key2;
...@@ -2273,8 +2260,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2273,8 +2260,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
*/ */
if (q.pi_state && (q.pi_state->owner != current)) { if (q.pi_state && (q.pi_state->owner != current)) {
spin_lock(q.lock_ptr); spin_lock(q.lock_ptr);
ret = fixup_pi_state_owner(uaddr2, &q, current, ret = fixup_pi_state_owner(uaddr2, &q, current);
fshared);
spin_unlock(q.lock_ptr); spin_unlock(q.lock_ptr);
} }
} else { } else {
...@@ -2293,7 +2279,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2293,7 +2279,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
* Fixup the pi_state owner and possibly acquire the lock if we * Fixup the pi_state owner and possibly acquire the lock if we
* haven't already. * haven't already.
*/ */
res = fixup_owner(uaddr2, fshared, &q, !ret); res = fixup_owner(uaddr2, &q, !ret);
/* /*
* If fixup_owner() returned an error, proprogate that. If it * If fixup_owner() returned an error, proprogate that. If it
* acquired the lock, clear -ETIMEDOUT or -EINTR. * acquired the lock, clear -ETIMEDOUT or -EINTR.
...@@ -2324,9 +2310,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, ...@@ -2324,9 +2310,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
} }
out_put_keys: out_put_keys:
put_futex_key(fshared, &q.key); put_futex_key(&q.key);
out_key2: out_key2:
put_futex_key(fshared, &key2); put_futex_key(&key2);
out: out:
if (to) { if (to) {
...@@ -2551,58 +2537,57 @@ void exit_robust_list(struct task_struct *curr) ...@@ -2551,58 +2537,57 @@ void exit_robust_list(struct task_struct *curr)
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3) u32 __user *uaddr2, u32 val2, u32 val3)
{ {
int clockrt, ret = -ENOSYS; int ret = -ENOSYS, cmd = op & FUTEX_CMD_MASK;
int cmd = op & FUTEX_CMD_MASK; unsigned int flags = 0;
int fshared = 0;
if (!(op & FUTEX_PRIVATE_FLAG)) if (!(op & FUTEX_PRIVATE_FLAG))
fshared = 1; flags |= FLAGS_SHARED;
clockrt = op & FUTEX_CLOCK_REALTIME; if (op & FUTEX_CLOCK_REALTIME) {
if (clockrt && cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI) flags |= FLAGS_CLOCKRT;
return -ENOSYS; if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
return -ENOSYS;
}
switch (cmd) { switch (cmd) {
case FUTEX_WAIT: case FUTEX_WAIT:
val3 = FUTEX_BITSET_MATCH_ANY; val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAIT_BITSET: case FUTEX_WAIT_BITSET:
ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt); ret = futex_wait(uaddr, flags, val, timeout, val3);
break; break;
case FUTEX_WAKE: case FUTEX_WAKE:
val3 = FUTEX_BITSET_MATCH_ANY; val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAKE_BITSET: case FUTEX_WAKE_BITSET:
ret = futex_wake(uaddr, fshared, val, val3); ret = futex_wake(uaddr, flags, val, val3);
break; break;
case FUTEX_REQUEUE: case FUTEX_REQUEUE:
ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL, 0); ret = futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
break; break;
case FUTEX_CMP_REQUEUE: case FUTEX_CMP_REQUEUE:
ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3, ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
0);
break; break;
case FUTEX_WAKE_OP: case FUTEX_WAKE_OP:
ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3); ret = futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
break; break;
case FUTEX_LOCK_PI: case FUTEX_LOCK_PI:
if (futex_cmpxchg_enabled) if (futex_cmpxchg_enabled)
ret = futex_lock_pi(uaddr, fshared, val, timeout, 0); ret = futex_lock_pi(uaddr, flags, val, timeout, 0);
break; break;
case FUTEX_UNLOCK_PI: case FUTEX_UNLOCK_PI:
if (futex_cmpxchg_enabled) if (futex_cmpxchg_enabled)
ret = futex_unlock_pi(uaddr, fshared); ret = futex_unlock_pi(uaddr, flags);
break; break;
case FUTEX_TRYLOCK_PI: case FUTEX_TRYLOCK_PI:
if (futex_cmpxchg_enabled) if (futex_cmpxchg_enabled)
ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1); ret = futex_lock_pi(uaddr, flags, 0, timeout, 1);
break; break;
case FUTEX_WAIT_REQUEUE_PI: case FUTEX_WAIT_REQUEUE_PI:
val3 = FUTEX_BITSET_MATCH_ANY; val3 = FUTEX_BITSET_MATCH_ANY;
ret = futex_wait_requeue_pi(uaddr, fshared, val, timeout, val3, ret = futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
clockrt, uaddr2); uaddr2);
break; break;
case FUTEX_CMP_REQUEUE_PI: case FUTEX_CMP_REQUEUE_PI:
ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3, ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
1);
break; break;
default: default:
ret = -ENOSYS; ret = -ENOSYS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment