aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2014-01-22 06:59:18 -0500
committerIngo Molnar <mingo@kernel.org>2014-01-23 08:48:36 -0500
commitd375b4e0fa3771343b370be0d876a1963c02e0a0 (patch)
tree21a015cf741235bb4a74d4ecae0e3d0b1cd4c32a /kernel
parent215393bc1fab3d61a5a296838bdffce22f27ffda (diff)
sched/clock: Fixup early initialization
The code would assume sched_clock_stable() and switch to !stable later, this switch brings a discontinuity in time. The discontinuity on switching from stable to unstable was always present, but previously we would set stable/unstable before initializing TSC and usually stick to the one we start out with. So the static_key bits brought an extra switch where there previously wasn't one. Things are further complicated by the fact that we cannot use static_key as early as we usually call set_sched_clock_stable(). Fix things by tracking the stable state in a regular variable and only set the static_key to the right state on sched_clock_init(), which is ran right after late_time_init->tsc_init(). Before this we would not be using the TSC anyway. Reported-and-Tested-by: Sasha Levin <sasha.levin@oracle.com> Reported-by: dyoung@redhat.com Fixes: 35af99e646c7 ("sched/clock, x86: Use a static_key for sched_clock_stable") Cc: jacob.jun.pan@linux.intel.com Cc: Mike Galbraith <bitbucket@online.de> Cc: hpa@zytor.com Cc: paulmck@linux.vnet.ibm.com Cc: John Stultz <john.stultz@linaro.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: lenb@kernel.org Cc: rjw@rjwysocki.net Cc: Eliezer Tamir <eliezer.tamir@linux.intel.com> Cc: rui.zhang@intel.com Signed-off-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20140122115918.GG3694@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/clock.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c
index 6bd6a6731b21..43c2bcc35761 100644
--- a/kernel/sched/clock.c
+++ b/kernel/sched/clock.c
@@ -77,35 +77,50 @@ __read_mostly int sched_clock_running;
77 77
78#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK 78#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
79static struct static_key __sched_clock_stable = STATIC_KEY_INIT; 79static struct static_key __sched_clock_stable = STATIC_KEY_INIT;
80static int __sched_clock_stable_early;
80 81
81int sched_clock_stable(void) 82int sched_clock_stable(void)
82{ 83{
83 if (static_key_false(&__sched_clock_stable)) 84 return static_key_false(&__sched_clock_stable);
84 return false;
85 return true;
86} 85}
87 86
88void set_sched_clock_stable(void) 87static void __set_sched_clock_stable(void)
89{ 88{
90 if (!sched_clock_stable()) 89 if (!sched_clock_stable())
91 static_key_slow_dec(&__sched_clock_stable); 90 static_key_slow_inc(&__sched_clock_stable);
91}
92
93void set_sched_clock_stable(void)
94{
95 __sched_clock_stable_early = 1;
96
97 smp_mb(); /* matches sched_clock_init() */
98
99 if (!sched_clock_running)
100 return;
101
102 __set_sched_clock_stable();
92} 103}
93 104
94static void __clear_sched_clock_stable(struct work_struct *work) 105static void __clear_sched_clock_stable(struct work_struct *work)
95{ 106{
96 /* XXX worry about clock continuity */ 107 /* XXX worry about clock continuity */
97 if (sched_clock_stable()) 108 if (sched_clock_stable())
98 static_key_slow_inc(&__sched_clock_stable); 109 static_key_slow_dec(&__sched_clock_stable);
99} 110}
100 111
101static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable); 112static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable);
102 113
103void clear_sched_clock_stable(void) 114void clear_sched_clock_stable(void)
104{ 115{
105 if (keventd_up()) 116 __sched_clock_stable_early = 0;
106 schedule_work(&sched_clock_work); 117
107 else 118 smp_mb(); /* matches sched_clock_init() */
108 __clear_sched_clock_stable(&sched_clock_work); 119
120 if (!sched_clock_running)
121 return;
122
123 schedule_work(&sched_clock_work);
109} 124}
110 125
111struct sched_clock_data { 126struct sched_clock_data {
@@ -140,6 +155,20 @@ void sched_clock_init(void)
140 } 155 }
141 156
142 sched_clock_running = 1; 157 sched_clock_running = 1;
158
159 /*
160 * Ensure that it is impossible to not do a static_key update.
161 *
162 * Either {set,clear}_sched_clock_stable() must see sched_clock_running
163 * and do the update, or we must see their __sched_clock_stable_early
164 * and do the update, or both.
165 */
166 smp_mb(); /* matches {set,clear}_sched_clock_stable() */
167
168 if (__sched_clock_stable_early)
169 __set_sched_clock_stable();
170 else
171 __clear_sched_clock_stable(NULL);
143} 172}
144 173
145/* 174/*
@@ -340,7 +369,7 @@ EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
340 */ 369 */
341u64 cpu_clock(int cpu) 370u64 cpu_clock(int cpu)
342{ 371{
343 if (static_key_false(&__sched_clock_stable)) 372 if (!sched_clock_stable())
344 return sched_clock_cpu(cpu); 373 return sched_clock_cpu(cpu);
345 374
346 return sched_clock(); 375 return sched_clock();
@@ -355,7 +384,7 @@ u64 cpu_clock(int cpu)
355 */ 384 */
356u64 local_clock(void) 385u64 local_clock(void)
357{ 386{
358 if (static_key_false(&__sched_clock_stable)) 387 if (!sched_clock_stable())
359 return sched_clock_cpu(raw_smp_processor_id()); 388 return sched_clock_cpu(raw_smp_processor_id());
360 389
361 return sched_clock(); 390 return sched_clock();