diff options
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch')
-rw-r--r-- | recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch new file mode 100644 index 00000000..5042065c --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch | |||
@@ -0,0 +1,349 @@ | |||
1 | From 19aeba1469884ed9a789b143cf73ce047663c095 Mon Sep 17 00:00:00 2001 | ||
2 | From: John Stultz <john.stultz@linaro.org> | ||
3 | Date: Tue, 17 Jul 2012 03:05:14 -0400 | ||
4 | Subject: [PATCH 074/109] ntp: Fix leap-second hrtimer livelock | ||
5 | |||
6 | This is a backport of 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d | ||
7 | |||
8 | This should have been backported when it was commited, but I | ||
9 | mistook the problem as requiring the ntp_lock changes | ||
10 | that landed in 3.4 in order for it to occur. | ||
11 | |||
12 | Unfortunately the same issue can happen (with only one cpu) | ||
13 | as follows: | ||
14 | do_adjtimex() | ||
15 | write_seqlock_irq(&xtime_lock); | ||
16 | process_adjtimex_modes() | ||
17 | process_adj_status() | ||
18 | ntp_start_leap_timer() | ||
19 | hrtimer_start() | ||
20 | hrtimer_reprogram() | ||
21 | tick_program_event() | ||
22 | clockevents_program_event() | ||
23 | ktime_get() | ||
24 | seq = req_seqbegin(xtime_lock); [DEADLOCK] | ||
25 | |||
26 | This deadlock will no always occur, as it requires the | ||
27 | leap_timer to force a hrtimer_reprogram which only happens | ||
28 | if its set and there's no sooner timer to expire. | ||
29 | |||
30 | NOTE: This patch, being faithful to the original commit, | ||
31 | introduces a bug (we don't update wall_to_monotonic), | ||
32 | which will be resovled by backporting a following fix. | ||
33 | |||
34 | Original commit message below: | ||
35 | |||
36 | Since commit 7dffa3c673fbcf835cd7be80bb4aec8ad3f51168 the ntp | ||
37 | subsystem has used an hrtimer for triggering the leapsecond | ||
38 | adjustment. However, this can cause a potential livelock. | ||
39 | |||
40 | Thomas diagnosed this as the following pattern: | ||
41 | CPU 0 CPU 1 | ||
42 | do_adjtimex() | ||
43 | spin_lock_irq(&ntp_lock); | ||
44 | process_adjtimex_modes(); timer_interrupt() | ||
45 | process_adj_status(); do_timer() | ||
46 | ntp_start_leap_timer(); write_lock(&xtime_lock); | ||
47 | hrtimer_start(); update_wall_time(); | ||
48 | hrtimer_reprogram(); ntp_tick_length() | ||
49 | tick_program_event() spin_lock(&ntp_lock); | ||
50 | clockevents_program_event() | ||
51 | ktime_get() | ||
52 | seq = req_seqbegin(xtime_lock); | ||
53 | |||
54 | This patch tries to avoid the problem by reverting back to not using | ||
55 | an hrtimer to inject leapseconds, and instead we handle the leapsecond | ||
56 | processing in the second_overflow() function. | ||
57 | |||
58 | The downside to this change is that on systems that support highres | ||
59 | timers, the leap second processing will occur on a HZ tick boundary, | ||
60 | (ie: ~1-10ms, depending on HZ) after the leap second instead of | ||
61 | possibly sooner (~34us in my tests w/ x86_64 lapic). | ||
62 | |||
63 | This patch applies on top of tip/timers/core. | ||
64 | |||
65 | CC: Sasha Levin <levinsasha928@gmail.com> | ||
66 | CC: Thomas Gleixner <tglx@linutronix.de> | ||
67 | Reported-by: Sasha Levin <levinsasha928@gmail.com> | ||
68 | Diagnoised-by: Thomas Gleixner <tglx@linutronix.de> | ||
69 | Tested-by: Sasha Levin <levinsasha928@gmail.com> | ||
70 | Cc: Prarit Bhargava <prarit@redhat.com> | ||
71 | Cc: Thomas Gleixner <tglx@linutronix.de> | ||
72 | Cc: Linux Kernel <linux-kernel@vger.kernel.org> | ||
73 | Signed-off-by: John Stultz <john.stultz@linaro.org> | ||
74 | Signed-off-by: Ben Hutchings <ben@decadent.org.uk> | ||
75 | --- | ||
76 | include/linux/timex.h | 2 +- | ||
77 | kernel/time/ntp.c | 122 +++++++++++++++------------------------------ | ||
78 | kernel/time/timekeeping.c | 18 +++---- | ||
79 | 3 files changed, 48 insertions(+), 94 deletions(-) | ||
80 | |||
81 | diff --git a/include/linux/timex.h b/include/linux/timex.h | ||
82 | index aa60fe7..08e90fb 100644 | ||
83 | --- a/include/linux/timex.h | ||
84 | +++ b/include/linux/timex.h | ||
85 | @@ -266,7 +266,7 @@ static inline int ntp_synced(void) | ||
86 | /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ | ||
87 | extern u64 tick_length; | ||
88 | |||
89 | -extern void second_overflow(void); | ||
90 | +extern int second_overflow(unsigned long secs); | ||
91 | extern void update_ntp_one_tick(void); | ||
92 | extern int do_adjtimex(struct timex *); | ||
93 | extern void hardpps(const struct timespec *, const struct timespec *); | ||
94 | diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c | ||
95 | index 4b85a7a..4508f7f 100644 | ||
96 | --- a/kernel/time/ntp.c | ||
97 | +++ b/kernel/time/ntp.c | ||
98 | @@ -31,8 +31,6 @@ unsigned long tick_nsec; | ||
99 | u64 tick_length; | ||
100 | static u64 tick_length_base; | ||
101 | |||
102 | -static struct hrtimer leap_timer; | ||
103 | - | ||
104 | #define MAX_TICKADJ 500LL /* usecs */ | ||
105 | #define MAX_TICKADJ_SCALED \ | ||
106 | (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) | ||
107 | @@ -350,60 +348,60 @@ void ntp_clear(void) | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | - * Leap second processing. If in leap-insert state at the end of the | ||
112 | - * day, the system clock is set back one second; if in leap-delete | ||
113 | - * state, the system clock is set ahead one second. | ||
114 | + * this routine handles the overflow of the microsecond field | ||
115 | + * | ||
116 | + * The tricky bits of code to handle the accurate clock support | ||
117 | + * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. | ||
118 | + * They were originally developed for SUN and DEC kernels. | ||
119 | + * All the kudos should go to Dave for this stuff. | ||
120 | + * | ||
121 | + * Also handles leap second processing, and returns leap offset | ||
122 | */ | ||
123 | -static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer) | ||
124 | +int second_overflow(unsigned long secs) | ||
125 | { | ||
126 | - enum hrtimer_restart res = HRTIMER_NORESTART; | ||
127 | - | ||
128 | - write_seqlock(&xtime_lock); | ||
129 | + int leap = 0; | ||
130 | + s64 delta; | ||
131 | |||
132 | + /* | ||
133 | + * Leap second processing. If in leap-insert state at the end of the | ||
134 | + * day, the system clock is set back one second; if in leap-delete | ||
135 | + * state, the system clock is set ahead one second. | ||
136 | + */ | ||
137 | switch (time_state) { | ||
138 | case TIME_OK: | ||
139 | + if (time_status & STA_INS) | ||
140 | + time_state = TIME_INS; | ||
141 | + else if (time_status & STA_DEL) | ||
142 | + time_state = TIME_DEL; | ||
143 | break; | ||
144 | case TIME_INS: | ||
145 | - timekeeping_leap_insert(-1); | ||
146 | - time_state = TIME_OOP; | ||
147 | - printk(KERN_NOTICE | ||
148 | - "Clock: inserting leap second 23:59:60 UTC\n"); | ||
149 | - hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC); | ||
150 | - res = HRTIMER_RESTART; | ||
151 | + if (secs % 86400 == 0) { | ||
152 | + leap = -1; | ||
153 | + time_state = TIME_OOP; | ||
154 | + printk(KERN_NOTICE | ||
155 | + "Clock: inserting leap second 23:59:60 UTC\n"); | ||
156 | + } | ||
157 | break; | ||
158 | case TIME_DEL: | ||
159 | - timekeeping_leap_insert(1); | ||
160 | - time_tai--; | ||
161 | - time_state = TIME_WAIT; | ||
162 | - printk(KERN_NOTICE | ||
163 | - "Clock: deleting leap second 23:59:59 UTC\n"); | ||
164 | + if ((secs + 1) % 86400 == 0) { | ||
165 | + leap = 1; | ||
166 | + time_tai--; | ||
167 | + time_state = TIME_WAIT; | ||
168 | + printk(KERN_NOTICE | ||
169 | + "Clock: deleting leap second 23:59:59 UTC\n"); | ||
170 | + } | ||
171 | break; | ||
172 | case TIME_OOP: | ||
173 | time_tai++; | ||
174 | time_state = TIME_WAIT; | ||
175 | - /* fall through */ | ||
176 | + break; | ||
177 | + | ||
178 | case TIME_WAIT: | ||
179 | if (!(time_status & (STA_INS | STA_DEL))) | ||
180 | time_state = TIME_OK; | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | - write_sequnlock(&xtime_lock); | ||
185 | - | ||
186 | - return res; | ||
187 | -} | ||
188 | - | ||
189 | -/* | ||
190 | - * this routine handles the overflow of the microsecond field | ||
191 | - * | ||
192 | - * The tricky bits of code to handle the accurate clock support | ||
193 | - * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. | ||
194 | - * They were originally developed for SUN and DEC kernels. | ||
195 | - * All the kudos should go to Dave for this stuff. | ||
196 | - */ | ||
197 | -void second_overflow(void) | ||
198 | -{ | ||
199 | - s64 delta; | ||
200 | |||
201 | /* Bump the maxerror field */ | ||
202 | time_maxerror += MAXFREQ / NSEC_PER_USEC; | ||
203 | @@ -423,23 +421,25 @@ void second_overflow(void) | ||
204 | pps_dec_valid(); | ||
205 | |||
206 | if (!time_adjust) | ||
207 | - return; | ||
208 | + goto out; | ||
209 | |||
210 | if (time_adjust > MAX_TICKADJ) { | ||
211 | time_adjust -= MAX_TICKADJ; | ||
212 | tick_length += MAX_TICKADJ_SCALED; | ||
213 | - return; | ||
214 | + goto out; | ||
215 | } | ||
216 | |||
217 | if (time_adjust < -MAX_TICKADJ) { | ||
218 | time_adjust += MAX_TICKADJ; | ||
219 | tick_length -= MAX_TICKADJ_SCALED; | ||
220 | - return; | ||
221 | + goto out; | ||
222 | } | ||
223 | |||
224 | tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) | ||
225 | << NTP_SCALE_SHIFT; | ||
226 | time_adjust = 0; | ||
227 | +out: | ||
228 | + return leap; | ||
229 | } | ||
230 | |||
231 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | ||
232 | @@ -501,27 +501,6 @@ static void notify_cmos_timer(void) | ||
233 | static inline void notify_cmos_timer(void) { } | ||
234 | #endif | ||
235 | |||
236 | -/* | ||
237 | - * Start the leap seconds timer: | ||
238 | - */ | ||
239 | -static inline void ntp_start_leap_timer(struct timespec *ts) | ||
240 | -{ | ||
241 | - long now = ts->tv_sec; | ||
242 | - | ||
243 | - if (time_status & STA_INS) { | ||
244 | - time_state = TIME_INS; | ||
245 | - now += 86400 - now % 86400; | ||
246 | - hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); | ||
247 | - | ||
248 | - return; | ||
249 | - } | ||
250 | - | ||
251 | - if (time_status & STA_DEL) { | ||
252 | - time_state = TIME_DEL; | ||
253 | - now += 86400 - (now + 1) % 86400; | ||
254 | - hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); | ||
255 | - } | ||
256 | -} | ||
257 | |||
258 | /* | ||
259 | * Propagate a new txc->status value into the NTP state: | ||
260 | @@ -546,22 +525,6 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) | ||
261 | time_status &= STA_RONLY; | ||
262 | time_status |= txc->status & ~STA_RONLY; | ||
263 | |||
264 | - switch (time_state) { | ||
265 | - case TIME_OK: | ||
266 | - ntp_start_leap_timer(ts); | ||
267 | - break; | ||
268 | - case TIME_INS: | ||
269 | - case TIME_DEL: | ||
270 | - time_state = TIME_OK; | ||
271 | - ntp_start_leap_timer(ts); | ||
272 | - case TIME_WAIT: | ||
273 | - if (!(time_status & (STA_INS | STA_DEL))) | ||
274 | - time_state = TIME_OK; | ||
275 | - break; | ||
276 | - case TIME_OOP: | ||
277 | - hrtimer_restart(&leap_timer); | ||
278 | - break; | ||
279 | - } | ||
280 | } | ||
281 | /* | ||
282 | * Called with the xtime lock held, so we can access and modify | ||
283 | @@ -643,9 +606,6 @@ int do_adjtimex(struct timex *txc) | ||
284 | (txc->tick < 900000/USER_HZ || | ||
285 | txc->tick > 1100000/USER_HZ)) | ||
286 | return -EINVAL; | ||
287 | - | ||
288 | - if (txc->modes & ADJ_STATUS && time_state != TIME_OK) | ||
289 | - hrtimer_cancel(&leap_timer); | ||
290 | } | ||
291 | |||
292 | if (txc->modes & ADJ_SETOFFSET) { | ||
293 | @@ -967,6 +927,4 @@ __setup("ntp_tick_adj=", ntp_tick_adj_setup); | ||
294 | void __init ntp_init(void) | ||
295 | { | ||
296 | ntp_clear(); | ||
297 | - hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); | ||
298 | - leap_timer.function = ntp_leap_second; | ||
299 | } | ||
300 | diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c | ||
301 | index 2378413..4780a7d 100644 | ||
302 | --- a/kernel/time/timekeeping.c | ||
303 | +++ b/kernel/time/timekeeping.c | ||
304 | @@ -169,15 +169,6 @@ static struct timespec raw_time; | ||
305 | /* flag for if timekeeping is suspended */ | ||
306 | int __read_mostly timekeeping_suspended; | ||
307 | |||
308 | -/* must hold xtime_lock */ | ||
309 | -void timekeeping_leap_insert(int leapsecond) | ||
310 | -{ | ||
311 | - xtime.tv_sec += leapsecond; | ||
312 | - wall_to_monotonic.tv_sec -= leapsecond; | ||
313 | - update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock, | ||
314 | - timekeeper.mult); | ||
315 | -} | ||
316 | - | ||
317 | /** | ||
318 | * timekeeping_forward_now - update clock to the current time | ||
319 | * | ||
320 | @@ -942,9 +933,11 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) | ||
321 | |||
322 | timekeeper.xtime_nsec += timekeeper.xtime_interval << shift; | ||
323 | while (timekeeper.xtime_nsec >= nsecps) { | ||
324 | + int leap; | ||
325 | timekeeper.xtime_nsec -= nsecps; | ||
326 | xtime.tv_sec++; | ||
327 | - second_overflow(); | ||
328 | + leap = second_overflow(xtime.tv_sec); | ||
329 | + xtime.tv_sec += leap; | ||
330 | } | ||
331 | |||
332 | /* Accumulate raw time */ | ||
333 | @@ -1050,9 +1043,12 @@ static void update_wall_time(void) | ||
334 | * xtime.tv_nsec isn't larger then NSEC_PER_SEC | ||
335 | */ | ||
336 | if (unlikely(xtime.tv_nsec >= NSEC_PER_SEC)) { | ||
337 | + int leap; | ||
338 | xtime.tv_nsec -= NSEC_PER_SEC; | ||
339 | xtime.tv_sec++; | ||
340 | - second_overflow(); | ||
341 | + leap = second_overflow(xtime.tv_sec); | ||
342 | + xtime.tv_sec += leap; | ||
343 | + | ||
344 | } | ||
345 | |||
346 | /* check to see if there is a new clocksource to use */ | ||
347 | -- | ||
348 | 1.7.7.6 | ||
349 | |||