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 | /** |