diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
| -rw-r--r-- | kernel/time/timekeeping.c | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index baeeb5c87cf1..48b9fffabdc2 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -25,6 +25,11 @@ | |||
| 25 | 25 | ||
| 26 | #include "tick-internal.h" | 26 | #include "tick-internal.h" |
| 27 | #include "ntp_internal.h" | 27 | #include "ntp_internal.h" |
| 28 | #include "timekeeping_internal.h" | ||
| 29 | |||
| 30 | #define TK_CLEAR_NTP (1 << 0) | ||
| 31 | #define TK_MIRROR (1 << 1) | ||
| 32 | #define TK_CLOCK_WAS_SET (1 << 2) | ||
| 28 | 33 | ||
| 29 | static struct timekeeper timekeeper; | 34 | static struct timekeeper timekeeper; |
| 30 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); | 35 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); |
| @@ -200,9 +205,9 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) | |||
| 200 | 205 | ||
| 201 | static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); | 206 | static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); |
| 202 | 207 | ||
| 203 | static void update_pvclock_gtod(struct timekeeper *tk) | 208 | static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) |
| 204 | { | 209 | { |
| 205 | raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk); | 210 | raw_notifier_call_chain(&pvclock_gtod_chain, was_set, tk); |
| 206 | } | 211 | } |
| 207 | 212 | ||
| 208 | /** | 213 | /** |
| @@ -216,7 +221,7 @@ int pvclock_gtod_register_notifier(struct notifier_block *nb) | |||
| 216 | 221 | ||
| 217 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 222 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
| 218 | ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); | 223 | ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); |
| 219 | update_pvclock_gtod(tk); | 224 | update_pvclock_gtod(tk, true); |
| 220 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 225 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 221 | 226 | ||
| 222 | return ret; | 227 | return ret; |
| @@ -241,16 +246,16 @@ int pvclock_gtod_unregister_notifier(struct notifier_block *nb) | |||
| 241 | EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); | 246 | EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); |
| 242 | 247 | ||
| 243 | /* must hold timekeeper_lock */ | 248 | /* must hold timekeeper_lock */ |
| 244 | static void timekeeping_update(struct timekeeper *tk, bool clearntp, bool mirror) | 249 | static void timekeeping_update(struct timekeeper *tk, unsigned int action) |
| 245 | { | 250 | { |
| 246 | if (clearntp) { | 251 | if (action & TK_CLEAR_NTP) { |
| 247 | tk->ntp_error = 0; | 252 | tk->ntp_error = 0; |
| 248 | ntp_clear(); | 253 | ntp_clear(); |
| 249 | } | 254 | } |
| 250 | update_vsyscall(tk); | 255 | update_vsyscall(tk); |
| 251 | update_pvclock_gtod(tk); | 256 | update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); |
| 252 | 257 | ||
| 253 | if (mirror) | 258 | if (action & TK_MIRROR) |
| 254 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); | 259 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); |
| 255 | } | 260 | } |
| 256 | 261 | ||
| @@ -508,7 +513,7 @@ int do_settimeofday(const struct timespec *tv) | |||
| 508 | 513 | ||
| 509 | tk_set_xtime(tk, tv); | 514 | tk_set_xtime(tk, tv); |
| 510 | 515 | ||
| 511 | timekeeping_update(tk, true, true); | 516 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
| 512 | 517 | ||
| 513 | write_seqcount_end(&timekeeper_seq); | 518 | write_seqcount_end(&timekeeper_seq); |
| 514 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 519 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -552,7 +557,7 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
| 552 | 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)); |
| 553 | 558 | ||
| 554 | 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 */ |
| 555 | timekeeping_update(tk, true, true); | 560 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
| 556 | 561 | ||
| 557 | write_seqcount_end(&timekeeper_seq); | 562 | write_seqcount_end(&timekeeper_seq); |
| 558 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 563 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -627,13 +632,22 @@ static int change_clocksource(void *data) | |||
| 627 | write_seqcount_begin(&timekeeper_seq); | 632 | write_seqcount_begin(&timekeeper_seq); |
| 628 | 633 | ||
| 629 | timekeeping_forward_now(tk); | 634 | timekeeping_forward_now(tk); |
| 630 | if (!new->enable || new->enable(new) == 0) { | 635 | /* |
| 631 | old = tk->clock; | 636 | * If the cs is in module, get a module reference. Succeeds |
| 632 | tk_setup_internals(tk, new); | 637 | * for built-in code (owner == NULL) as well. |
| 633 | if (old->disable) | 638 | */ |
| 634 | old->disable(old); | 639 | if (try_module_get(new->owner)) { |
| 640 | if (!new->enable || new->enable(new) == 0) { | ||
| 641 | old = tk->clock; | ||
| 642 | tk_setup_internals(tk, new); | ||
| 643 | if (old->disable) | ||
| 644 | old->disable(old); | ||
| 645 | module_put(old->owner); | ||
| 646 | } else { | ||
| 647 | module_put(new->owner); | ||
| 648 | } | ||
| 635 | } | 649 | } |
| 636 | timekeeping_update(tk, true, true); | 650 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
| 637 | 651 | ||
| 638 | write_seqcount_end(&timekeeper_seq); | 652 | write_seqcount_end(&timekeeper_seq); |
| 639 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 653 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -648,14 +662,15 @@ static int change_clocksource(void *data) | |||
| 648 | * This function is called from clocksource.c after a new, better clock | 662 | * This function is called from clocksource.c after a new, better clock |
| 649 | * source has been registered. The caller holds the clocksource_mutex. | 663 | * source has been registered. The caller holds the clocksource_mutex. |
| 650 | */ | 664 | */ |
| 651 | void timekeeping_notify(struct clocksource *clock) | 665 | int timekeeping_notify(struct clocksource *clock) |
| 652 | { | 666 | { |
| 653 | struct timekeeper *tk = &timekeeper; | 667 | struct timekeeper *tk = &timekeeper; |
| 654 | 668 | ||
| 655 | if (tk->clock == clock) | 669 | if (tk->clock == clock) |
| 656 | return; | 670 | return 0; |
| 657 | stop_machine(change_clocksource, clock, NULL); | 671 | stop_machine(change_clocksource, clock, NULL); |
| 658 | tick_clock_notify(); | 672 | tick_clock_notify(); |
| 673 | return tk->clock == clock ? 0 : -1; | ||
| 659 | } | 674 | } |
| 660 | 675 | ||
| 661 | /** | 676 | /** |
| @@ -841,6 +856,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, | |||
| 841 | tk_xtime_add(tk, delta); | 856 | tk_xtime_add(tk, delta); |
| 842 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta)); | 857 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta)); |
| 843 | tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta)); | 858 | tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta)); |
| 859 | tk_debug_account_sleep_time(delta); | ||
| 844 | } | 860 | } |
| 845 | 861 | ||
| 846 | /** | 862 | /** |
| @@ -872,7 +888,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta) | |||
| 872 | 888 | ||
| 873 | __timekeeping_inject_sleeptime(tk, delta); | 889 | __timekeeping_inject_sleeptime(tk, delta); |
| 874 | 890 | ||
| 875 | timekeeping_update(tk, true, true); | 891 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
| 876 | 892 | ||
| 877 | write_seqcount_end(&timekeeper_seq); | 893 | write_seqcount_end(&timekeeper_seq); |
| 878 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 894 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -954,7 +970,7 @@ static void timekeeping_resume(void) | |||
| 954 | tk->cycle_last = clock->cycle_last = cycle_now; | 970 | tk->cycle_last = clock->cycle_last = cycle_now; |
| 955 | tk->ntp_error = 0; | 971 | tk->ntp_error = 0; |
| 956 | timekeeping_suspended = 0; | 972 | timekeeping_suspended = 0; |
| 957 | timekeeping_update(tk, false, true); | 973 | timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); |
| 958 | write_seqcount_end(&timekeeper_seq); | 974 | write_seqcount_end(&timekeeper_seq); |
| 959 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 975 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 960 | 976 | ||
| @@ -1236,9 +1252,10 @@ out_adjust: | |||
| 1236 | * It also calls into the NTP code to handle leapsecond processing. | 1252 | * It also calls into the NTP code to handle leapsecond processing. |
| 1237 | * | 1253 | * |
| 1238 | */ | 1254 | */ |
| 1239 | static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) | 1255 | static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) |
| 1240 | { | 1256 | { |
| 1241 | u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; | 1257 | u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; |
| 1258 | unsigned int action = 0; | ||
| 1242 | 1259 | ||
| 1243 | while (tk->xtime_nsec >= nsecps) { | 1260 | while (tk->xtime_nsec >= nsecps) { |
| 1244 | int leap; | 1261 | int leap; |
| @@ -1261,8 +1278,10 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) | |||
| 1261 | __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); | 1278 | __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); |
| 1262 | 1279 | ||
| 1263 | clock_was_set_delayed(); | 1280 | clock_was_set_delayed(); |
| 1281 | action = TK_CLOCK_WAS_SET; | ||
| 1264 | } | 1282 | } |
| 1265 | } | 1283 | } |
| 1284 | return action; | ||
| 1266 | } | 1285 | } |
| 1267 | 1286 | ||
| 1268 | /** | 1287 | /** |
| @@ -1347,6 +1366,7 @@ static void update_wall_time(void) | |||
| 1347 | struct timekeeper *tk = &shadow_timekeeper; | 1366 | struct timekeeper *tk = &shadow_timekeeper; |
| 1348 | cycle_t offset; | 1367 | cycle_t offset; |
| 1349 | int shift = 0, maxshift; | 1368 | int shift = 0, maxshift; |
| 1369 | unsigned int action; | ||
| 1350 | unsigned long flags; | 1370 | unsigned long flags; |
| 1351 | 1371 | ||
| 1352 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1372 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
| @@ -1399,7 +1419,7 @@ static void update_wall_time(void) | |||
| 1399 | * Finally, make sure that after the rounding | 1419 | * Finally, make sure that after the rounding |
| 1400 | * xtime_nsec isn't larger than NSEC_PER_SEC | 1420 | * xtime_nsec isn't larger than NSEC_PER_SEC |
| 1401 | */ | 1421 | */ |
| 1402 | accumulate_nsecs_to_secs(tk); | 1422 | action = accumulate_nsecs_to_secs(tk); |
| 1403 | 1423 | ||
| 1404 | write_seqcount_begin(&timekeeper_seq); | 1424 | write_seqcount_begin(&timekeeper_seq); |
| 1405 | /* Update clock->cycle_last with the new value */ | 1425 | /* Update clock->cycle_last with the new value */ |
| @@ -1415,7 +1435,7 @@ static void update_wall_time(void) | |||
| 1415 | * updating. | 1435 | * updating. |
| 1416 | */ | 1436 | */ |
| 1417 | memcpy(real_tk, tk, sizeof(*tk)); | 1437 | memcpy(real_tk, tk, sizeof(*tk)); |
| 1418 | timekeeping_update(real_tk, false, false); | 1438 | timekeeping_update(real_tk, action); |
| 1419 | write_seqcount_end(&timekeeper_seq); | 1439 | write_seqcount_end(&timekeeper_seq); |
| 1420 | out: | 1440 | out: |
| 1421 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 1441 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -1677,6 +1697,7 @@ int do_adjtimex(struct timex *txc) | |||
| 1677 | 1697 | ||
| 1678 | if (tai != orig_tai) { | 1698 | if (tai != orig_tai) { |
| 1679 | __timekeeping_set_tai_offset(tk, tai); | 1699 | __timekeeping_set_tai_offset(tk, tai); |
| 1700 | update_pvclock_gtod(tk, true); | ||
| 1680 | clock_was_set_delayed(); | 1701 | clock_was_set_delayed(); |
| 1681 | } | 1702 | } |
| 1682 | write_seqcount_end(&timekeeper_seq); | 1703 | write_seqcount_end(&timekeeper_seq); |
