Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

timekeeping: Indicate that clock was set in the pvclock gtod notifier

If the clock was set (stepped), set the action parameter to functions
in the pvclock gtod notifier chain to non-zero. This allows the
callee to only do work if the clock was stepped.

This will be used on Xen as the synchronization of the Xen wallclock
to the control domain's (dom0) system time will be done with this
notifier and updating on every timer tick is unnecessary and too
expensive.

Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: <xen-devel@lists.xen.org>
Link: http://lkml.kernel.org/r/1372329348-20841-4-git-send-email-david.vrabel@citrix.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

David Vrabel and committed by
Thomas Gleixner
780427f0 04397fe9

+25 -12
+7
include/linux/pvclock_gtod.h
··· 3 3 4 4 #include <linux/notifier.h> 5 5 6 + /* 7 + * The pvclock gtod notifier is called when the system time is updated 8 + * and is used to keep guest time synchronized with host time. 9 + * 10 + * The 'action' parameter in the notifier function is false (0), or 11 + * true (non-zero) if system time was stepped. 12 + */ 6 13 extern int pvclock_gtod_register_notifier(struct notifier_block *nb); 7 14 extern int pvclock_gtod_unregister_notifier(struct notifier_block *nb); 8 15
+18 -12
kernel/time/timekeeping.c
··· 29 29 30 30 #define TK_CLEAR_NTP (1 << 0) 31 31 #define TK_MIRROR (1 << 1) 32 + #define TK_CLOCK_WAS_SET (1 << 2) 32 33 33 34 static struct timekeeper timekeeper; 34 35 static DEFINE_RAW_SPINLOCK(timekeeper_lock); ··· 205 204 206 205 static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); 207 206 208 - static void update_pvclock_gtod(struct timekeeper *tk) 207 + static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) 209 208 { 210 - raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk); 209 + raw_notifier_call_chain(&pvclock_gtod_chain, was_set, tk); 211 210 } 212 211 213 212 /** ··· 221 220 222 221 raw_spin_lock_irqsave(&timekeeper_lock, flags); 223 222 ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); 224 - update_pvclock_gtod(tk); 223 + update_pvclock_gtod(tk, true); 225 224 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); 226 225 227 226 return ret; ··· 253 252 ntp_clear(); 254 253 } 255 254 update_vsyscall(tk); 256 - update_pvclock_gtod(tk); 255 + update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); 257 256 258 257 if (action & TK_MIRROR) 259 258 memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); ··· 513 512 514 513 tk_set_xtime(tk, tv); 515 514 516 - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); 515 + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); 517 516 518 517 write_seqcount_end(&timekeeper_seq); 519 518 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); ··· 557 556 tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); 558 557 559 558 error: /* even if we error out, we forwarded the time, so call update */ 560 - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); 559 + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); 561 560 562 561 write_seqcount_end(&timekeeper_seq); 563 562 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); ··· 647 646 module_put(new->owner); 648 647 } 649 648 } 650 - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); 649 + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); 651 650 652 651 write_seqcount_end(&timekeeper_seq); 653 652 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); ··· 888 887 889 888 __timekeeping_inject_sleeptime(tk, delta); 890 889 891 - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR); 890 + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); 892 891 893 892 write_seqcount_end(&timekeeper_seq); 894 893 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); ··· 970 969 tk->cycle_last = clock->cycle_last = cycle_now; 971 970 tk->ntp_error = 0; 972 971 timekeeping_suspended = 0; 973 - timekeeping_update(tk, TK_MIRROR); 972 + timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); 974 973 write_seqcount_end(&timekeeper_seq); 975 974 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); 976 975 ··· 1244 1243 * It also calls into the NTP code to handle leapsecond processing. 1245 1244 * 1246 1245 */ 1247 - static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) 1246 + static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) 1248 1247 { 1249 1248 u64 nsecps = (u64)NSEC_PER_SEC << tk->shift; 1249 + unsigned int action = 0; 1250 1250 1251 1251 while (tk->xtime_nsec >= nsecps) { 1252 1252 int leap; ··· 1270 1268 __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); 1271 1269 1272 1270 clock_was_set_delayed(); 1271 + action = TK_CLOCK_WAS_SET; 1273 1272 } 1274 1273 } 1274 + return action; 1275 1275 } 1276 1276 1277 1277 /** ··· 1358 1354 struct timekeeper *tk = &shadow_timekeeper; 1359 1355 cycle_t offset; 1360 1356 int shift = 0, maxshift; 1357 + unsigned int action; 1361 1358 unsigned long flags; 1362 1359 1363 1360 raw_spin_lock_irqsave(&timekeeper_lock, flags); ··· 1411 1406 * Finally, make sure that after the rounding 1412 1407 * xtime_nsec isn't larger than NSEC_PER_SEC 1413 1408 */ 1414 - accumulate_nsecs_to_secs(tk); 1409 + action = accumulate_nsecs_to_secs(tk); 1415 1410 1416 1411 write_seqcount_begin(&timekeeper_seq); 1417 1412 /* Update clock->cycle_last with the new value */ ··· 1427 1422 * updating. 1428 1423 */ 1429 1424 memcpy(real_tk, tk, sizeof(*tk)); 1430 - timekeeping_update(real_tk, 0); 1425 + timekeeping_update(real_tk, action); 1431 1426 write_seqcount_end(&timekeeper_seq); 1432 1427 out: 1433 1428 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); ··· 1689 1684 1690 1685 if (tai != orig_tai) { 1691 1686 __timekeeping_set_tai_offset(tk, tai); 1687 + update_pvclock_gtod(tk, true); 1692 1688 clock_was_set_delayed(); 1693 1689 } 1694 1690 write_seqcount_end(&timekeeper_seq);