Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7193bea5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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: Detect mismatched requeue targets
  futex: Correct futex_wait_requeue_pi() commentary
parents 989aa44a 84bc4af5
Loading
Loading
Loading
Loading
+30 −17
Original line number Diff line number Diff line
@@ -115,6 +115,9 @@ struct futex_q {
	/* rt_waiter storage for requeue_pi: */
	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 */
	u32 bitset;
};
@@ -1089,6 +1092,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
	if (!top_waiter)
		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
	 * the contended case or if set_waiters is 1.  The pi_state is returned
@@ -1276,6 +1283,12 @@ static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
			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
		 * 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.bitset = bitset;
	q.rt_waiter = NULL;
	q.requeue_pi_key = NULL;

	if (abs_time) {
		to = &timeout;
@@ -1858,6 +1872,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,

	q.pi_state = NULL;
	q.rt_waiter = NULL;
	q.requeue_pi_key = NULL;
retry:
	q.key = FUTEX_KEY_INIT;
	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
 * via the following:
 * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
 * 2) wakeup on uaddr2 after a requeue and subsequent unlock
 * 3) signal (before or after requeue)
 * 4) timeout (before or after requeue)
 * 2) wakeup on uaddr2 after a requeue
 * 3) signal
 * 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:
 * 5) successful lock
@@ -2130,7 +2145,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
 * 7) timeout
 * 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.
 *
@@ -2169,15 +2184,16 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
	debug_rt_mutex_init_waiter(&rt_waiter);
	rt_waiter.task = NULL;

	q.pi_state = NULL;
	q.bitset = bitset;
	q.rt_waiter = &rt_waiter;

	key2 = FUTEX_KEY_INIT;
	ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
	if (unlikely(ret != 0))
		goto out;

	q.pi_state = NULL;
	q.bitset = bitset;
	q.rt_waiter = &rt_waiter;
	q.requeue_pi_key = &key2;

	/* Prepare to wait on uaddr. */
	ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
	if (ret)
@@ -2248,14 +2264,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
			rt_mutex_unlock(pi_mutex);
	} else if (ret == -EINTR) {
		/*
		 * We've already been requeued, but we have no way to
		 * restart by calling futex_lock_pi() directly. We
		 * could restart the syscall, but that will look at
		 * the user space value and return right away. So we
		 * drop back with EWOULDBLOCK to tell user space that
		 * "val" has been changed. That's the same what the
		 * restart of the syscall would do in
		 * futex_wait_setup().
		 * We've already been requeued, but cannot restart by calling
		 * futex_lock_pi() directly. We could restart this syscall, but
		 * it would detect that the user space "val" changed and return
		 * -EWOULDBLOCK.  Save the overhead of the restart and return
		 * -EWOULDBLOCK directly.
		 */
		ret = -EWOULDBLOCK;
	}