aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2013-06-27 06:35:47 -0400
committerThomas Gleixner <tglx@linutronix.de>2013-06-28 17:15:06 -0400
commit5584880e44e49c587059801faa2a9f7d22619c48 (patch)
tree46e21fede52e74d90287705a1d86ff1498d205ce
parent780427f0e113b4c77dfff4d258c05a902cdb0eb9 (diff)
x86: xen: Sync the wallclock when the system time is set
Currently the Xen wallclock is only updated every 11 minutes if NTP is synchronized to its clock source (using the sync_cmos_clock() work). If a guest is started before NTP is synchronized it may see an incorrect wallclock time. Use the pvclock_gtod notifier chain to receive a notification when the system time has changed and update the wallclock to match. This chain is called on every timer tick and we want to avoid an extra (expensive) hypercall on every tick. Because dom0 has historically never provided a very accurate wallclock and guests do not expect one, we can do this simply: the wallclock is only updated if the clock was set. 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-5-git-send-email-david.vrabel@citrix.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/xen/time.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index a1947ac2da82..3364850d23e6 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -14,6 +14,7 @@
14#include <linux/kernel_stat.h> 14#include <linux/kernel_stat.h>
15#include <linux/math64.h> 15#include <linux/math64.h>
16#include <linux/gfp.h> 16#include <linux/gfp.h>
17#include <linux/pvclock_gtod.h>
17 18
18#include <asm/pvclock.h> 19#include <asm/pvclock.h>
19#include <asm/xen/hypervisor.h> 20#include <asm/xen/hypervisor.h>
@@ -212,6 +213,30 @@ static int xen_set_wallclock(const struct timespec *now)
212 return HYPERVISOR_dom0_op(&op); 213 return HYPERVISOR_dom0_op(&op);
213} 214}
214 215
216static int xen_pvclock_gtod_notify(struct notifier_block *nb, unsigned long was_set,
217 void *priv)
218{
219 struct timespec now;
220 struct xen_platform_op op;
221
222 if (!was_set)
223 return NOTIFY_OK;
224
225 now = __current_kernel_time();
226
227 op.cmd = XENPF_settime;
228 op.u.settime.secs = now.tv_sec;
229 op.u.settime.nsecs = now.tv_nsec;
230 op.u.settime.system_time = xen_clocksource_read();
231
232 (void)HYPERVISOR_dom0_op(&op);
233 return NOTIFY_OK;
234}
235
236static struct notifier_block xen_pvclock_gtod_notifier = {
237 .notifier_call = xen_pvclock_gtod_notify,
238};
239
215static struct clocksource xen_clocksource __read_mostly = { 240static struct clocksource xen_clocksource __read_mostly = {
216 .name = "xen", 241 .name = "xen",
217 .rating = 400, 242 .rating = 400,
@@ -473,6 +498,9 @@ static void __init xen_time_init(void)
473 xen_setup_runstate_info(cpu); 498 xen_setup_runstate_info(cpu);
474 xen_setup_timer(cpu); 499 xen_setup_timer(cpu);
475 xen_setup_cpu_clockevents(); 500 xen_setup_cpu_clockevents();
501
502 if (xen_initial_domain())
503 pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
476} 504}
477 505
478void __init xen_init_time_ops(void) 506void __init xen_init_time_ops(void)