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

Commit 5083fb83 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Greg Kroah-Hartman
Browse files

futex: Fix (possible) missed wakeup



commit b061c38bef43406df8e73c5be06cbfacad5ee6ad upstream.

We must not rely on wake_q_add() to delay the wakeup; in particular
commit:

  1d0dcb3a ("futex: Implement lockless wakeups")

moved wake_q_add() before smp_store_release(&q->lock_ptr, NULL), which
could result in futex_wait() waking before observing ->lock_ptr ==
NULL and going back to sleep again.

Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: 1d0dcb3a ("futex: Implement lockless wakeups")
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b4f92d8d
Loading
Loading
Loading
Loading
+8 −5
Original line number Original line Diff line number Diff line
@@ -1553,11 +1553,7 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
	if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))
	if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))
		return;
		return;


	/*
	get_task_struct(p);
	 * Queue the task for later wakeup for after we've released
	 * the hb->lock. wake_q_add() grabs reference to p.
	 */
	wake_q_add(wake_q, p);
	__unqueue_futex(q);
	__unqueue_futex(q);
	/*
	/*
	 * The waiting task can free the futex_q as soon as
	 * The waiting task can free the futex_q as soon as
@@ -1566,6 +1562,13 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
	 * store to lock_ptr from getting ahead of the plist_del.
	 * store to lock_ptr from getting ahead of the plist_del.
	 */
	 */
	smp_store_release(&q->lock_ptr, NULL);
	smp_store_release(&q->lock_ptr, NULL);

	/*
	 * Queue the task for later wakeup for after we've released
	 * the hb->lock. wake_q_add() grabs reference to p.
	 */
	wake_q_add(wake_q, p);
	put_task_struct(p);
}
}


/*
/*