diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2012-03-20 10:57:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-03-27 08:50:14 -0400 |
commit | 2baab4e90495ebc9826c93f79d74d6e60a828d24 (patch) | |
tree | 6e6316694a9bc69e517e50b0d01043c4c9e83888 /include/linux/cpuset.h | |
parent | bc758133ed73d4b06952bec21da23e28e62bf3ba (diff) |
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux/cpuset.h')
-rw-r--r-- | include/linux/cpuset.h | 6 |
1 files changed, 2 insertions, 4 deletions
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index e9eaec522655..e0ffaf061ab7 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h | |||
@@ -22,7 +22,7 @@ extern int cpuset_init(void); | |||
22 | extern void cpuset_init_smp(void); | 22 | extern void cpuset_init_smp(void); |
23 | extern void cpuset_update_active_cpus(void); | 23 | extern void cpuset_update_active_cpus(void); |
24 | extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask); | 24 | extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask); |
25 | extern int cpuset_cpus_allowed_fallback(struct task_struct *p); | 25 | extern void cpuset_cpus_allowed_fallback(struct task_struct *p); |
26 | extern nodemask_t cpuset_mems_allowed(struct task_struct *p); | 26 | extern nodemask_t cpuset_mems_allowed(struct task_struct *p); |
27 | #define cpuset_current_mems_allowed (current->mems_allowed) | 27 | #define cpuset_current_mems_allowed (current->mems_allowed) |
28 | void cpuset_init_current_mems_allowed(void); | 28 | void cpuset_init_current_mems_allowed(void); |
@@ -144,10 +144,8 @@ static inline void cpuset_cpus_allowed(struct task_struct *p, | |||
144 | cpumask_copy(mask, cpu_possible_mask); | 144 | cpumask_copy(mask, cpu_possible_mask); |
145 | } | 145 | } |
146 | 146 | ||
147 | static inline int cpuset_cpus_allowed_fallback(struct task_struct *p) | 147 | static inline void cpuset_cpus_allowed_fallback(struct task_struct *p) |
148 | { | 148 | { |
149 | do_set_cpus_allowed(p, cpu_possible_mask); | ||
150 | return cpumask_any(cpu_active_mask); | ||
151 | } | 149 | } |
152 | 150 | ||
153 | static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) | 151 | static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) |