aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2013-02-21 17:51:40 -0500
committerJohn Stultz <john.stultz@linaro.org>2013-04-04 16:18:32 -0400
commit48cdc135d4840aab8efd2fc3bacb5d7dfd94a9c8 (patch)
tree4ef4c34ff6312bb4dd9d381d3ba17c2aa5c7cfc8 /kernel/time/timekeeping.c
parent7ec98e15aa049b7a2ca73485f31cf4f90c34e2dd (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>
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c41
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 @@
29static struct timekeeper timekeeper; 29static struct timekeeper timekeeper;
30static DEFINE_RAW_SPINLOCK(timekeeper_lock); 30static DEFINE_RAW_SPINLOCK(timekeeper_lock);
31static seqcount_t timekeeper_seq; 31static seqcount_t timekeeper_seq;
32static struct timekeeper shadow_timekeeper;
32 33
33/* flag for if timekeeping is suspended */ 34/* flag for if timekeeping is suspended */
34int __read_mostly timekeeping_suspended; 35int __read_mostly timekeeping_suspended;
@@ -240,7 +241,7 @@ int pvclock_gtod_unregister_notifier(struct notifier_block *nb)
240EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); 241EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
241 242
242/* must hold timekeeper_lock */ 243/* must hold timekeeper_lock */
243static void timekeeping_update(struct timekeeper *tk, bool clearntp) 244static 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
550error: /* even if we error out, we forwarded the time, so call update */ 554error: /* 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)
1328static void update_wall_time(void) 1334static 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
1393out: 1411out:
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/**