]>
Commit | Line | Data |
---|---|---|
9aa60b56 SL |
1 | From 55a9c23935eff6b602ffb80552d3ddf0dafcd6d7 Mon Sep 17 00:00:00 2001 |
2 | From: Peter Zijlstra <peterz@infradead.org> | |
3 | Date: Thu, 29 Nov 2018 14:44:49 +0100 | |
4 | Subject: futex: Fix (possible) missed wakeup | |
5 | ||
6 | [ Upstream commit b061c38bef43406df8e73c5be06cbfacad5ee6ad ] | |
7 | ||
8 | We must not rely on wake_q_add() to delay the wakeup; in particular | |
9 | commit: | |
10 | ||
11 | 1d0dcb3ad9d3 ("futex: Implement lockless wakeups") | |
12 | ||
13 | moved wake_q_add() before smp_store_release(&q->lock_ptr, NULL), which | |
14 | could result in futex_wait() waking before observing ->lock_ptr == | |
15 | NULL and going back to sleep again. | |
16 | ||
17 | Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> | |
18 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
19 | Cc: Peter Zijlstra <peterz@infradead.org> | |
20 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
21 | Fixes: 1d0dcb3ad9d3 ("futex: Implement lockless wakeups") | |
22 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
23 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
24 | --- | |
25 | kernel/futex.c | 13 ++++++++----- | |
26 | 1 file changed, 8 insertions(+), 5 deletions(-) | |
27 | ||
28 | diff --git a/kernel/futex.c b/kernel/futex.c | |
29 | index 29d708d0b3d19..22f83064abb35 100644 | |
30 | --- a/kernel/futex.c | |
31 | +++ b/kernel/futex.c | |
32 | @@ -1462,11 +1462,7 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q) | |
33 | if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) | |
34 | return; | |
35 | ||
36 | - /* | |
37 | - * Queue the task for later wakeup for after we've released | |
38 | - * the hb->lock. wake_q_add() grabs reference to p. | |
39 | - */ | |
40 | - wake_q_add(wake_q, p); | |
41 | + get_task_struct(p); | |
42 | __unqueue_futex(q); | |
43 | /* | |
44 | * The waiting task can free the futex_q as soon as q->lock_ptr = NULL | |
45 | @@ -1476,6 +1472,13 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q) | |
46 | * plist_del in __unqueue_futex(). | |
47 | */ | |
48 | smp_store_release(&q->lock_ptr, NULL); | |
49 | + | |
50 | + /* | |
51 | + * Queue the task for later wakeup for after we've released | |
52 | + * the hb->lock. wake_q_add() grabs reference to p. | |
53 | + */ | |
54 | + wake_q_add(wake_q, p); | |
55 | + put_task_struct(p); | |
56 | } | |
57 | ||
58 | /* | |
59 | -- | |
60 | 2.19.1 | |
61 |