]>
Commit | Line | Data |
---|---|---|
cc6b8f45 GKH |
1 | From 0f397f2c90ce68821ee864c2c53baafe78de765d Mon Sep 17 00:00:00 2001 |
2 | From: Kirill Tkhai <tkhai@yandex.ru> | |
3 | Date: Tue, 20 May 2014 13:33:42 +0400 | |
4 | Subject: sched/dl: Fix race in dl_task_timer() | |
5 | ||
6 | From: Kirill Tkhai <tkhai@yandex.ru> | |
7 | ||
8 | commit 0f397f2c90ce68821ee864c2c53baafe78de765d upstream. | |
9 | ||
10 | Throttled task is still on rq, and it may be moved to other cpu | |
11 | if user is playing with sched_setaffinity(). Therefore, unlocked | |
12 | task_rq() access makes the race. | |
13 | ||
14 | Juri Lelli reports he got this race when dl_bandwidth_enabled() | |
15 | was not set. | |
16 | ||
17 | Other thing, pointed by Peter Zijlstra: | |
18 | ||
19 | "Now I suppose the problem can still actually happen when | |
20 | you change the root domain and trigger a effective affinity | |
21 | change that way". | |
22 | ||
23 | To fix that we do the same as made in __task_rq_lock(). We do not | |
24 | use __task_rq_lock() itself, because it has a useful lockdep check, | |
25 | which is not correct in case of dl_task_timer(). We do not need | |
26 | pi_lock locked here. This case is an exception (PeterZ): | |
27 | ||
28 | "The only reason we don't strictly need ->pi_lock now is because | |
29 | we're guaranteed to have p->state == TASK_RUNNING here and are | |
30 | thus free of ttwu races". | |
31 | ||
32 | Signed-off-by: Kirill Tkhai <tkhai@yandex.ru> | |
33 | Signed-off-by: Peter Zijlstra <peterz@infradead.org> | |
34 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
35 | Link: http://lkml.kernel.org/r/3056991400578422@web14g.yandex.ru | |
36 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
37 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
38 | ||
39 | --- | |
40 | kernel/sched/deadline.c | 10 +++++++++- | |
41 | 1 file changed, 9 insertions(+), 1 deletion(-) | |
42 | ||
43 | --- a/kernel/sched/deadline.c | |
44 | +++ b/kernel/sched/deadline.c | |
45 | @@ -490,9 +490,17 @@ static enum hrtimer_restart dl_task_time | |
46 | struct sched_dl_entity, | |
47 | dl_timer); | |
48 | struct task_struct *p = dl_task_of(dl_se); | |
49 | - struct rq *rq = task_rq(p); | |
50 | + struct rq *rq; | |
51 | +again: | |
52 | + rq = task_rq(p); | |
53 | raw_spin_lock(&rq->lock); | |
54 | ||
55 | + if (rq != task_rq(p)) { | |
56 | + /* Task was moved, retrying. */ | |
57 | + raw_spin_unlock(&rq->lock); | |
58 | + goto again; | |
59 | + } | |
60 | + | |
61 | /* | |
62 | * We need to take care of a possible races here. In fact, the | |
63 | * task might have changed its scheduling policy to something |