diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-06-20 14:18:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-06-20 14:18:35 -0400 |
commit | a3d5c3460a86f52ea435b3fb98be112bd18faabc (patch) | |
tree | 48a32968b569af0e0f0af1def3effa0770710fea | |
parent | 86c76676cfdbf283f6131d5a2783bed3f3d490ea (diff) | |
parent | 29bb9e5a75684106a37593ad75ec75ff8312731b (diff) |
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fixes from Ingo Molnar:
"Two smaller fixes - plus a context tracking tracing fix that is a bit
bigger"
* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
tracing/context-tracking: Add preempt_schedule_context() for tracing
sched: Fix clear NOHZ_BALANCE_KICK
sched/x86: Construct all sibling maps if smt
-rw-r--r-- | arch/x86/kernel/smpboot.c | 8 | ||||
-rw-r--r-- | include/linux/preempt.h | 18 | ||||
-rw-r--r-- | kernel/context_tracking.c | 40 | ||||
-rw-r--r-- | kernel/sched/core.c | 21 |
4 files changed, 78 insertions, 9 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 9c73b51817e4..bfd348e99369 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -372,15 +372,15 @@ static bool __cpuinit match_mc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o) | |||
372 | 372 | ||
373 | void __cpuinit set_cpu_sibling_map(int cpu) | 373 | void __cpuinit set_cpu_sibling_map(int cpu) |
374 | { | 374 | { |
375 | bool has_mc = boot_cpu_data.x86_max_cores > 1; | ||
376 | bool has_smt = smp_num_siblings > 1; | 375 | bool has_smt = smp_num_siblings > 1; |
376 | bool has_mp = has_smt || boot_cpu_data.x86_max_cores > 1; | ||
377 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 377 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
378 | struct cpuinfo_x86 *o; | 378 | struct cpuinfo_x86 *o; |
379 | int i; | 379 | int i; |
380 | 380 | ||
381 | cpumask_set_cpu(cpu, cpu_sibling_setup_mask); | 381 | cpumask_set_cpu(cpu, cpu_sibling_setup_mask); |
382 | 382 | ||
383 | if (!has_smt && !has_mc) { | 383 | if (!has_mp) { |
384 | cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); | 384 | cpumask_set_cpu(cpu, cpu_sibling_mask(cpu)); |
385 | cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu)); | 385 | cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu)); |
386 | cpumask_set_cpu(cpu, cpu_core_mask(cpu)); | 386 | cpumask_set_cpu(cpu, cpu_core_mask(cpu)); |
@@ -394,7 +394,7 @@ void __cpuinit set_cpu_sibling_map(int cpu) | |||
394 | if ((i == cpu) || (has_smt && match_smt(c, o))) | 394 | if ((i == cpu) || (has_smt && match_smt(c, o))) |
395 | link_mask(sibling, cpu, i); | 395 | link_mask(sibling, cpu, i); |
396 | 396 | ||
397 | if ((i == cpu) || (has_mc && match_llc(c, o))) | 397 | if ((i == cpu) || (has_mp && match_llc(c, o))) |
398 | link_mask(llc_shared, cpu, i); | 398 | link_mask(llc_shared, cpu, i); |
399 | 399 | ||
400 | } | 400 | } |
@@ -406,7 +406,7 @@ void __cpuinit set_cpu_sibling_map(int cpu) | |||
406 | for_each_cpu(i, cpu_sibling_setup_mask) { | 406 | for_each_cpu(i, cpu_sibling_setup_mask) { |
407 | o = &cpu_data(i); | 407 | o = &cpu_data(i); |
408 | 408 | ||
409 | if ((i == cpu) || (has_mc && match_mc(c, o))) { | 409 | if ((i == cpu) || (has_mp && match_mc(c, o))) { |
410 | link_mask(core, cpu, i); | 410 | link_mask(core, cpu, i); |
411 | 411 | ||
412 | /* | 412 | /* |
diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 87a03c746f17..f5d4723cdb3d 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h | |||
@@ -33,9 +33,25 @@ do { \ | |||
33 | preempt_schedule(); \ | 33 | preempt_schedule(); \ |
34 | } while (0) | 34 | } while (0) |
35 | 35 | ||
36 | #ifdef CONFIG_CONTEXT_TRACKING | ||
37 | |||
38 | void preempt_schedule_context(void); | ||
39 | |||
40 | #define preempt_check_resched_context() \ | ||
41 | do { \ | ||
42 | if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ | ||
43 | preempt_schedule_context(); \ | ||
44 | } while (0) | ||
45 | #else | ||
46 | |||
47 | #define preempt_check_resched_context() preempt_check_resched() | ||
48 | |||
49 | #endif /* CONFIG_CONTEXT_TRACKING */ | ||
50 | |||
36 | #else /* !CONFIG_PREEMPT */ | 51 | #else /* !CONFIG_PREEMPT */ |
37 | 52 | ||
38 | #define preempt_check_resched() do { } while (0) | 53 | #define preempt_check_resched() do { } while (0) |
54 | #define preempt_check_resched_context() do { } while (0) | ||
39 | 55 | ||
40 | #endif /* CONFIG_PREEMPT */ | 56 | #endif /* CONFIG_PREEMPT */ |
41 | 57 | ||
@@ -88,7 +104,7 @@ do { \ | |||
88 | do { \ | 104 | do { \ |
89 | preempt_enable_no_resched_notrace(); \ | 105 | preempt_enable_no_resched_notrace(); \ |
90 | barrier(); \ | 106 | barrier(); \ |
91 | preempt_check_resched(); \ | 107 | preempt_check_resched_context(); \ |
92 | } while (0) | 108 | } while (0) |
93 | 109 | ||
94 | #else /* !CONFIG_PREEMPT_COUNT */ | 110 | #else /* !CONFIG_PREEMPT_COUNT */ |
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c index 85bdde1137eb..383f8231e436 100644 --- a/kernel/context_tracking.c +++ b/kernel/context_tracking.c | |||
@@ -70,6 +70,46 @@ void user_enter(void) | |||
70 | local_irq_restore(flags); | 70 | local_irq_restore(flags); |
71 | } | 71 | } |
72 | 72 | ||
73 | #ifdef CONFIG_PREEMPT | ||
74 | /** | ||
75 | * preempt_schedule_context - preempt_schedule called by tracing | ||
76 | * | ||
77 | * The tracing infrastructure uses preempt_enable_notrace to prevent | ||
78 | * recursion and tracing preempt enabling caused by the tracing | ||
79 | * infrastructure itself. But as tracing can happen in areas coming | ||
80 | * from userspace or just about to enter userspace, a preempt enable | ||
81 | * can occur before user_exit() is called. This will cause the scheduler | ||
82 | * to be called when the system is still in usermode. | ||
83 | * | ||
84 | * To prevent this, the preempt_enable_notrace will use this function | ||
85 | * instead of preempt_schedule() to exit user context if needed before | ||
86 | * calling the scheduler. | ||
87 | */ | ||
88 | void __sched notrace preempt_schedule_context(void) | ||
89 | { | ||
90 | struct thread_info *ti = current_thread_info(); | ||
91 | enum ctx_state prev_ctx; | ||
92 | |||
93 | if (likely(ti->preempt_count || irqs_disabled())) | ||
94 | return; | ||
95 | |||
96 | /* | ||
97 | * Need to disable preemption in case user_exit() is traced | ||
98 | * and the tracer calls preempt_enable_notrace() causing | ||
99 | * an infinite recursion. | ||
100 | */ | ||
101 | preempt_disable_notrace(); | ||
102 | prev_ctx = exception_enter(); | ||
103 | preempt_enable_no_resched_notrace(); | ||
104 | |||
105 | preempt_schedule(); | ||
106 | |||
107 | preempt_disable_notrace(); | ||
108 | exception_exit(prev_ctx); | ||
109 | preempt_enable_notrace(); | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(preempt_schedule_context); | ||
112 | #endif /* CONFIG_PREEMPT */ | ||
73 | 113 | ||
74 | /** | 114 | /** |
75 | * user_exit - Inform the context tracking that the CPU is | 115 | * user_exit - Inform the context tracking that the CPU is |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e1a27f918723..e8b335016c52 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -633,7 +633,19 @@ void wake_up_nohz_cpu(int cpu) | |||
633 | static inline bool got_nohz_idle_kick(void) | 633 | static inline bool got_nohz_idle_kick(void) |
634 | { | 634 | { |
635 | int cpu = smp_processor_id(); | 635 | int cpu = smp_processor_id(); |
636 | return idle_cpu(cpu) && test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)); | 636 | |
637 | if (!test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu))) | ||
638 | return false; | ||
639 | |||
640 | if (idle_cpu(cpu) && !need_resched()) | ||
641 | return true; | ||
642 | |||
643 | /* | ||
644 | * We can't run Idle Load Balance on this CPU for this time so we | ||
645 | * cancel it and clear NOHZ_BALANCE_KICK | ||
646 | */ | ||
647 | clear_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)); | ||
648 | return false; | ||
637 | } | 649 | } |
638 | 650 | ||
639 | #else /* CONFIG_NO_HZ_COMMON */ | 651 | #else /* CONFIG_NO_HZ_COMMON */ |
@@ -1393,8 +1405,9 @@ static void sched_ttwu_pending(void) | |||
1393 | 1405 | ||
1394 | void scheduler_ipi(void) | 1406 | void scheduler_ipi(void) |
1395 | { | 1407 | { |
1396 | if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick() | 1408 | if (llist_empty(&this_rq()->wake_list) |
1397 | && !tick_nohz_full_cpu(smp_processor_id())) | 1409 | && !tick_nohz_full_cpu(smp_processor_id()) |
1410 | && !got_nohz_idle_kick()) | ||
1398 | return; | 1411 | return; |
1399 | 1412 | ||
1400 | /* | 1413 | /* |
@@ -1417,7 +1430,7 @@ void scheduler_ipi(void) | |||
1417 | /* | 1430 | /* |
1418 | * Check if someone kicked us for doing the nohz idle load balance. | 1431 | * Check if someone kicked us for doing the nohz idle load balance. |
1419 | */ | 1432 | */ |
1420 | if (unlikely(got_nohz_idle_kick() && !need_resched())) { | 1433 | if (unlikely(got_nohz_idle_kick())) { |
1421 | this_rq()->idle_balance = 1; | 1434 | this_rq()->idle_balance = 1; |
1422 | raise_softirq_irqoff(SCHED_SOFTIRQ); | 1435 | raise_softirq_irqoff(SCHED_SOFTIRQ); |
1423 | } | 1436 | } |