diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/timekeeping.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d8b23a929e66..846d0a1f235e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #define TK_CLEAR_NTP (1 << 0) | 30 | #define TK_CLEAR_NTP (1 << 0) |
31 | #define TK_MIRROR (1 << 1) | 31 | #define TK_MIRROR (1 << 1) |
32 | #define TK_CLOCK_WAS_SET (1 << 2) | ||
32 | 33 | ||
33 | static struct timekeeper timekeeper; | 34 | static struct timekeeper timekeeper; |
34 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); | 35 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); |
@@ -204,9 +205,9 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
204 | 205 | ||
205 | static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); | 206 | static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); |
206 | 207 | ||
207 | static void update_pvclock_gtod(struct timekeeper *tk) | 208 | static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) |
208 | { | 209 | { |
209 | raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk); | 210 | raw_notifier_call_chain(&pvclock_gtod_chain, was_set, tk); |
210 | } | 211 | } |
211 | 212 | ||
212 | /** | 213 | /** |
@@ -220,7 +221,7 @@ int pvclock_gtod_register_notifier(struct notifier_block *nb) | |||
220 | 221 | ||
221 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 222 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
222 | ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); | 223 | ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); |
223 | update_pvclock_gtod(tk); | 224 | update_pvclock_gtod(tk, true); |
224 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 225 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
225 | 226 | ||
226 | return ret; | 227 | return ret; |
@@ -252,7 +253,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) | |||
252 | ntp_clear(); | 253 | ntp_clear(); |
253 | } | 254 | } |
254 | update_vsyscall(tk); | 255 | update_vsyscall(tk); |
255 | update_pvclock_gtod(tk); | 256 | update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); |
256 | 257 | ||
257 | if (action & TK_MIRROR) | 258 | if (action & TK_MIRROR) |
258 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); | 259 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); |
@@ -512,7 +513,7 @@ int do_settimeofday(const struct timespec *tv) | |||
512 | 513 | ||
513 | tk_set_xtime(tk, tv); | 514 | tk_set_xtime(tk, tv); |
514 | 515 | ||
515 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); | 516 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
516 | 517 | ||
517 | write_seqcount_end(&timekeeper_seq); | 518 | write_seqcount_end(&timekeeper_seq); |
518 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 519 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
@@ -556,7 +557,7 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
556 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); | 557 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); |
557 | 558 | ||
558 | error: /* even if we error out, we forwarded the time, so call update */ | 559 | error: /* even if we error out, we forwarded the time, so call update */ |
559 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); | 560 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
560 | 561 | ||
561 | write_seqcount_end(&timekeeper_seq); | 562 | write_seqcount_end(&timekeeper_seq); |
562 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 563 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
@@ -646,7 +647,7 @@ static int change_clocksource(void *data) | |||
646 | module_put(new->owner); | 647 | module_put(new->owner); |
647 | } | 648 | } |
648 | } | 649 | } |
649 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); | 650 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
650 | 651 | ||
651 | write_seqcount_end(&timekeeper_seq); | 652 | write_seqcount_end(&timekeeper_seq); |
652 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 653 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
@@ -887,7 +888,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta) | |||
887 | 888 | ||
888 | __timekeeping_inject_sleeptime(tk, delta); | 889 | __timekeeping_inject_sleeptime(tk, delta); |
889 | 890 | ||
890 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); | 891 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
891 | 892 | ||
892 | write_seqcount_end(&timekeeper_seq); | 893 | write_seqcount_end(&timekeeper_seq); |
893 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 894 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
@@ -969,7 +970,7 @@ static void timekeeping_resume(void) | |||
969 | tk->cycle_last = clock->cycle_last = cycle_now; | 970 | tk->cycle_last = clock->cycle_last = cycle_now; |
970 | tk->ntp_error = 0; | 971 | tk->ntp_error = 0; |
971 | timekeeping_suspended = 0; | 972 | timekeeping_suspended = 0; |
972 | timekeeping_update(tk, TK_MIRROR); | 973 | timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); |
973 | write_seqcount_end(&timekeeper_seq); | 974 | write_seqcount_end(&timekeeper_seq); |
974 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 975 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
975 | 976 | ||
@@ -1243,9 +1244,10 @@ out_adjust: | |||
1243 | * It also calls into the NTP code to handle leapsecond processing. | 1244 | * It also calls into the NTP code to handle leapsecond processing. |
1244 | * | 1245 | * |
1245 | */ | 1246 | */ |
1246 | static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) | 1247 | static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) |
1247 | { | 1248 | { |
1248 | u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; | 1249 | u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; |
1250 | unsigned int action = 0; | ||
1249 | 1251 | ||
1250 | while (tk->xtime_nsec >= nsecps) { | 1252 | while (tk->xtime_nsec >= nsecps) { |
1251 | int leap; | 1253 | int leap; |
@@ -1268,8 +1270,10 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) | |||
1268 | __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); | 1270 | __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); |
1269 | 1271 | ||
1270 | clock_was_set_delayed(); | 1272 | clock_was_set_delayed(); |
1273 | action = TK_CLOCK_WAS_SET; | ||
1271 | } | 1274 | } |
1272 | } | 1275 | } |
1276 | return action; | ||
1273 | } | 1277 | } |
1274 | 1278 | ||
1275 | /** | 1279 | /** |
@@ -1354,6 +1358,7 @@ static void update_wall_time(void) | |||
1354 | struct timekeeper *tk = &shadow_timekeeper; | 1358 | struct timekeeper *tk = &shadow_timekeeper; |
1355 | cycle_t offset; | 1359 | cycle_t offset; |
1356 | int shift = 0, maxshift; | 1360 | int shift = 0, maxshift; |
1361 | unsigned int action; | ||
1357 | unsigned long flags; | 1362 | unsigned long flags; |
1358 | 1363 | ||
1359 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1364 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
@@ -1406,7 +1411,7 @@ static void update_wall_time(void) | |||
1406 | * Finally, make sure that after the rounding | 1411 | * Finally, make sure that after the rounding |
1407 | * xtime_nsec isn't larger than NSEC_PER_SEC | 1412 | * xtime_nsec isn't larger than NSEC_PER_SEC |
1408 | */ | 1413 | */ |
1409 | accumulate_nsecs_to_secs(tk); | 1414 | action = accumulate_nsecs_to_secs(tk); |
1410 | 1415 | ||
1411 | write_seqcount_begin(&timekeeper_seq); | 1416 | write_seqcount_begin(&timekeeper_seq); |
1412 | /* Update clock->cycle_last with the new value */ | 1417 | /* Update clock->cycle_last with the new value */ |
@@ -1422,7 +1427,7 @@ static void update_wall_time(void) | |||
1422 | * updating. | 1427 | * updating. |
1423 | */ | 1428 | */ |
1424 | memcpy(real_tk, tk, sizeof(*tk)); | 1429 | memcpy(real_tk, tk, sizeof(*tk)); |
1425 | timekeeping_update(real_tk, 0); | 1430 | timekeeping_update(real_tk, action); |
1426 | write_seqcount_end(&timekeeper_seq); | 1431 | write_seqcount_end(&timekeeper_seq); |
1427 | out: | 1432 | out: |
1428 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 1433 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
@@ -1684,6 +1689,7 @@ int do_adjtimex(struct timex *txc) | |||
1684 | 1689 | ||
1685 | if (tai != orig_tai) { | 1690 | if (tai != orig_tai) { |
1686 | __timekeeping_set_tai_offset(tk, tai); | 1691 | __timekeeping_set_tai_offset(tk, tai); |
1692 | update_pvclock_gtod(tk, true); | ||
1687 | clock_was_set_delayed(); | 1693 | clock_was_set_delayed(); |
1688 | } | 1694 | } |
1689 | write_seqcount_end(&timekeeper_seq); | 1695 | write_seqcount_end(&timekeeper_seq); |