diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2013-02-21 17:51:40 -0500 |
|---|---|---|
| committer | John Stultz <john.stultz@linaro.org> | 2013-04-04 16:18:32 -0400 |
| commit | 48cdc135d4840aab8efd2fc3bacb5d7dfd94a9c8 (patch) | |
| tree | 4ef4c34ff6312bb4dd9d381d3ba17c2aa5c7cfc8 | |
| parent | 7ec98e15aa049b7a2ca73485f31cf4f90c34e2dd (diff) | |
timekeeping: Implement a shadow timekeeper
Use the shadow timekeeper to do the update_wall_time() adjustments and
then copy it over to the real timekeeper.
Keep the shadow timekeeper in sync when updating stuff outside of
update_wall_time().
This allows us to limit the timekeeper_seq hold time to the update of
the real timekeeper and the vsyscall data in the next patch.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
| -rw-r--r-- | kernel/time/timekeeping.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 38ac782c0ef8..d20ffdad62e8 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | static struct timekeeper timekeeper; | 29 | static struct timekeeper timekeeper; |
| 30 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); | 30 | static DEFINE_RAW_SPINLOCK(timekeeper_lock); |
| 31 | static seqcount_t timekeeper_seq; | 31 | static seqcount_t timekeeper_seq; |
| 32 | static struct timekeeper shadow_timekeeper; | ||
| 32 | 33 | ||
| 33 | /* flag for if timekeeping is suspended */ | 34 | /* flag for if timekeeping is suspended */ |
| 34 | int __read_mostly timekeeping_suspended; | 35 | int __read_mostly timekeeping_suspended; |
| @@ -240,7 +241,7 @@ int pvclock_gtod_unregister_notifier(struct notifier_block *nb) | |||
| 240 | EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); | 241 | EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); |
| 241 | 242 | ||
| 242 | /* must hold timekeeper_lock */ | 243 | /* must hold timekeeper_lock */ |
| 243 | static void timekeeping_update(struct timekeeper *tk, bool clearntp) | 244 | static void timekeeping_update(struct timekeeper *tk, bool clearntp, bool mirror) |
| 244 | { | 245 | { |
| 245 | if (clearntp) { | 246 | if (clearntp) { |
| 246 | tk->ntp_error = 0; | 247 | tk->ntp_error = 0; |
| @@ -248,6 +249,9 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp) | |||
| 248 | } | 249 | } |
| 249 | update_vsyscall(tk); | 250 | update_vsyscall(tk); |
| 250 | update_pvclock_gtod(tk); | 251 | update_pvclock_gtod(tk); |
| 252 | |||
| 253 | if (mirror) | ||
| 254 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); | ||
| 251 | } | 255 | } |
| 252 | 256 | ||
| 253 | /** | 257 | /** |
| @@ -504,7 +508,7 @@ int do_settimeofday(const struct timespec *tv) | |||
| 504 | 508 | ||
| 505 | tk_set_xtime(tk, tv); | 509 | tk_set_xtime(tk, tv); |
| 506 | 510 | ||
| 507 | timekeeping_update(tk, true); | 511 | timekeeping_update(tk, true, true); |
| 508 | 512 | ||
| 509 | write_seqcount_end(&timekeeper_seq); | 513 | write_seqcount_end(&timekeeper_seq); |
| 510 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 514 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -548,7 +552,7 @@ int timekeeping_inject_offset(struct timespec *ts) | |||
| 548 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); | 552 | tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); |
| 549 | 553 | ||
| 550 | error: /* even if we error out, we forwarded the time, so call update */ | 554 | error: /* even if we error out, we forwarded the time, so call update */ |
| 551 | timekeeping_update(tk, true); | 555 | timekeeping_update(tk, true, true); |
| 552 | 556 | ||
| 553 | write_seqcount_end(&timekeeper_seq); | 557 | write_seqcount_end(&timekeeper_seq); |
| 554 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 558 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -628,7 +632,7 @@ static int change_clocksource(void *data) | |||
| 628 | if (old->disable) | 632 | if (old->disable) |
| 629 | old->disable(old); | 633 | old->disable(old); |
| 630 | } | 634 | } |
| 631 | timekeeping_update(tk, true); | 635 | timekeeping_update(tk, true, true); |
| 632 | 636 | ||
| 633 | write_seqcount_end(&timekeeper_seq); | 637 | write_seqcount_end(&timekeeper_seq); |
| 634 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 638 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -809,6 +813,8 @@ void __init timekeeping_init(void) | |||
| 809 | tmp.tv_nsec = 0; | 813 | tmp.tv_nsec = 0; |
| 810 | tk_set_sleep_time(tk, tmp); | 814 | tk_set_sleep_time(tk, tmp); |
| 811 | 815 | ||
| 816 | memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); | ||
| 817 | |||
| 812 | write_seqcount_end(&timekeeper_seq); | 818 | write_seqcount_end(&timekeeper_seq); |
| 813 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 819 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 814 | } | 820 | } |
| @@ -865,7 +871,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta) | |||
| 865 | 871 | ||
| 866 | __timekeeping_inject_sleeptime(tk, delta); | 872 | __timekeeping_inject_sleeptime(tk, delta); |
| 867 | 873 | ||
| 868 | timekeeping_update(tk, true); | 874 | timekeeping_update(tk, true, true); |
| 869 | 875 | ||
| 870 | write_seqcount_end(&timekeeper_seq); | 876 | write_seqcount_end(&timekeeper_seq); |
| 871 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 877 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| @@ -947,7 +953,7 @@ static void timekeeping_resume(void) | |||
| 947 | clock->cycle_last = cycle_now; | 953 | clock->cycle_last = cycle_now; |
| 948 | tk->ntp_error = 0; | 954 | tk->ntp_error = 0; |
| 949 | timekeeping_suspended = 0; | 955 | timekeeping_suspended = 0; |
| 950 | timekeeping_update(tk, false); | 956 | timekeeping_update(tk, false, true); |
| 951 | write_seqcount_end(&timekeeper_seq); | 957 | write_seqcount_end(&timekeeper_seq); |
| 952 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 958 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 953 | 959 | ||
| @@ -1328,7 +1334,8 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk) | |||
| 1328 | static void update_wall_time(void) | 1334 | static void update_wall_time(void) |
| 1329 | { | 1335 | { |
| 1330 | struct clocksource *clock; | 1336 | struct clocksource *clock; |
| 1331 | struct timekeeper *tk = &timekeeper; | 1337 | struct timekeeper *real_tk = &timekeeper; |
| 1338 | struct timekeeper *tk = &shadow_timekeeper; | ||
| 1332 | cycle_t offset; | 1339 | cycle_t offset; |
| 1333 | int shift = 0, maxshift; | 1340 | int shift = 0, maxshift; |
| 1334 | unsigned long flags; | 1341 | unsigned long flags; |
| @@ -1340,16 +1347,16 @@ static void update_wall_time(void) | |||
| 1340 | if (unlikely(timekeeping_suspended)) | 1347 | if (unlikely(timekeeping_suspended)) |
| 1341 | goto out; | 1348 | goto out; |
| 1342 | 1349 | ||
| 1343 | clock = tk->clock; | 1350 | clock = real_tk->clock; |
| 1344 | 1351 | ||
| 1345 | #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET | 1352 | #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET |
| 1346 | offset = tk->cycle_interval; | 1353 | offset = real_tk->cycle_interval; |
| 1347 | #else | 1354 | #else |
| 1348 | offset = (clock->read(clock) - clock->cycle_last) & clock->mask; | 1355 | offset = (clock->read(clock) - clock->cycle_last) & clock->mask; |
| 1349 | #endif | 1356 | #endif |
| 1350 | 1357 | ||
| 1351 | /* Check if there's really nothing to do */ | 1358 | /* Check if there's really nothing to do */ |
| 1352 | if (offset < tk->cycle_interval) | 1359 | if (offset < real_tk->cycle_interval) |
| 1353 | goto out; | 1360 | goto out; |
| 1354 | 1361 | ||
| 1355 | /* | 1362 | /* |
| @@ -1388,12 +1395,22 @@ static void update_wall_time(void) | |||
| 1388 | 1395 | ||
| 1389 | /* Update clock->cycle_last with the new value */ | 1396 | /* Update clock->cycle_last with the new value */ |
| 1390 | clock->cycle_last = tk->cycle_last; | 1397 | clock->cycle_last = tk->cycle_last; |
| 1391 | timekeeping_update(tk, false); | 1398 | /* |
| 1399 | * Update the real timekeeper. | ||
| 1400 | * | ||
| 1401 | * We could avoid this memcpy by switching pointers, but that | ||
| 1402 | * requires changes to all other timekeeper usage sites as | ||
| 1403 | * well, i.e. move the timekeeper pointer getter into the | ||
| 1404 | * spinlocked/seqcount protected sections. And we trade this | ||
| 1405 | * memcpy under the timekeeper_seq against one before we start | ||
| 1406 | * updating. | ||
| 1407 | */ | ||
| 1408 | memcpy(real_tk, tk, sizeof(*tk)); | ||
| 1409 | timekeeping_update(real_tk, false, false); | ||
| 1392 | 1410 | ||
| 1393 | out: | 1411 | out: |
| 1394 | write_seqcount_end(&timekeeper_seq); | 1412 | write_seqcount_end(&timekeeper_seq); |
| 1395 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 1413 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
| 1396 | |||
| 1397 | } | 1414 | } |
| 1398 | 1415 | ||
| 1399 | /** | 1416 | /** |
