aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2011-02-02 07:19:09 -0500
committerIngo Molnar <mingo@elte.hu>2011-02-03 06:14:43 -0500
commitfe4b04fa31a6dcf4358aa84cf81e5a7fd079469b (patch)
tree20a6db874d0db2a2f2e38e3ff77df4bdaa5f1cfe /kernel/sched.c
parentb84defe6036e6dea782d41b80a4590e54f249671 (diff)
perf: Cure task_oncpu_function_call() races
Oleg reported that on architectures with __ARCH_WANT_INTERRUPTS_ON_CTXSW the IPI from task_oncpu_function_call() can land before perf_event_task_sched_in() and cause interesting situations for eg. perf_install_in_context(). This patch reworks the task_oncpu_function_call() interface to give a more usable primitive as well as rework all its users to hopefully be more obvious as well as remove the races. While looking at the code I also found a number of races against perf_event_task_sched_out() which can flip contexts between tasks so plug those too. Reported-and-reviewed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c29
1 files changed, 4 insertions, 25 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 18d38e4ec7ba..31cb5d5e1aac 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2265,27 +2265,6 @@ void kick_process(struct task_struct *p)
2265EXPORT_SYMBOL_GPL(kick_process); 2265EXPORT_SYMBOL_GPL(kick_process);
2266#endif /* CONFIG_SMP */ 2266#endif /* CONFIG_SMP */
2267 2267
2268/**
2269 * task_oncpu_function_call - call a function on the cpu on which a task runs
2270 * @p: the task to evaluate
2271 * @func: the function to be called
2272 * @info: the function call argument
2273 *
2274 * Calls the function @func when the task is currently running. This might
2275 * be on the current CPU, which just calls the function directly
2276 */
2277void task_oncpu_function_call(struct task_struct *p,
2278 void (*func) (void *info), void *info)
2279{
2280 int cpu;
2281
2282 preempt_disable();
2283 cpu = task_cpu(p);
2284 if (task_curr(p))
2285 smp_call_function_single(cpu, func, info, 1);
2286 preempt_enable();
2287}
2288
2289#ifdef CONFIG_SMP 2268#ifdef CONFIG_SMP
2290/* 2269/*
2291 * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held. 2270 * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held.
@@ -2776,9 +2755,12 @@ static inline void
2776prepare_task_switch(struct rq *rq, struct task_struct *prev, 2755prepare_task_switch(struct rq *rq, struct task_struct *prev,
2777 struct task_struct *next) 2756 struct task_struct *next)
2778{ 2757{
2758 sched_info_switch(prev, next);
2759 perf_event_task_sched_out(prev, next);
2779 fire_sched_out_preempt_notifiers(prev, next); 2760 fire_sched_out_preempt_notifiers(prev, next);
2780 prepare_lock_switch(rq, next); 2761 prepare_lock_switch(rq, next);
2781 prepare_arch_switch(next); 2762 prepare_arch_switch(next);
2763 trace_sched_switch(prev, next);
2782} 2764}
2783 2765
2784/** 2766/**
@@ -2911,7 +2893,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
2911 struct mm_struct *mm, *oldmm; 2893 struct mm_struct *mm, *oldmm;
2912 2894
2913 prepare_task_switch(rq, prev, next); 2895 prepare_task_switch(rq, prev, next);
2914 trace_sched_switch(prev, next); 2896
2915 mm = next->mm; 2897 mm = next->mm;
2916 oldmm = prev->active_mm; 2898 oldmm = prev->active_mm;
2917 /* 2899 /*
@@ -3989,9 +3971,6 @@ need_resched_nonpreemptible:
3989 rq->skip_clock_update = 0; 3971 rq->skip_clock_update = 0;
3990 3972
3991 if (likely(prev != next)) { 3973 if (likely(prev != next)) {
3992 sched_info_switch(prev, next);
3993 perf_event_task_sched_out(prev, next);
3994
3995 rq->nr_switches++; 3974 rq->nr_switches++;
3996 rq->curr = next; 3975 rq->curr = next;
3997 ++*switch_count; 3976 ++*switch_count;