All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [PVOPS] dom0 sync xen wallclock
@ 2010-02-09 18:12 Stefano Stabellini
  2010-02-09 18:20 ` Stefano Stabellini
  2010-02-10 23:09 ` Jeremy Fitzhardinge
  0 siblings, 2 replies; 17+ messages in thread
From: Stefano Stabellini @ 2010-02-09 18:12 UTC (permalink / raw)
  To: Jeremy Fitzhardinge; +Cc: xen-devel, Ian Campbell

Hi Jeremy,
this patch removes clock_was_set and adds an atomic notification chain
instead so that not only hrtimers but other parts of the kernel can be
notified of a time change as well.
In fact xen/time.c needs to be notified so that can update xen
wallclock time to keep it in sync; this is necessary otherwise other
PV guests will get a wrong wallclock time at boot.
Please let me know if my approach is suitable for upstream, I am willing
to do any change needed and to send the patch upstream myself if you
give me some directions.
Thanks,

Stefano

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

---

diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 0b56fd4..a0532ec 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -13,6 +13,7 @@
 #include <linux/clockchips.h>
 #include <linux/kernel_stat.h>
 #include <linux/math64.h>
+#include <linux/notifier.h>
 
 #include <asm/pvclock.h>
 #include <asm/xen/hypervisor.h>
@@ -526,6 +527,43 @@ static int __init xen_setup_vsyscall_timeinfo(int cpu)
 }
 #endif	/* CONFIG_PARAVIRT_CLOCK_VSYSCALL */
 
+static void sync_xen_wallclock(unsigned long dummy);
+static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0);
+static void sync_xen_wallclock(unsigned long dummy)
+{
+	struct xen_platform_op op;
+	struct timespec ts;
+
+	write_seqlock_irq(&xtime_lock);
+
+	set_normalized_timespec(&ts, xtime.tv_sec, xtime.tv_nsec);
+
+	op.cmd = XENPF_settime;
+	op.u.settime.secs        = ts.tv_sec;
+	op.u.settime.nsecs       = ts.tv_nsec;
+	op.u.settime.system_time = xen_clocksource_read();
+	WARN_ON(HYPERVISOR_dom0_op(&op));
+
+	write_sequnlock_irq(&xtime_lock);
+
+	/* Once per minute. */
+	mod_timer(&sync_xen_wallclock_timer, jiffies + 60*HZ);
+}
+
+int xen_update_persistent_clock(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	if (!xen_initial_domain())
+		return -1;
+	mod_timer(&sync_xen_wallclock_timer, jiffies + 1);
+	return 0;
+}
+
+static struct notifier_block xen_clock_was_set = {
+	.notifier_call  = xen_update_persistent_clock,
+};
+
+
 __init void xen_time_init(void)
 {
 	int cpu = smp_processor_id();
@@ -549,6 +587,8 @@ __init void xen_time_init(void)
 	xen_setup_runstate_info(cpu);
 	xen_setup_timer(cpu);
 	xen_setup_cpu_clockevents();
+	if (xen_initial_domain())
+		atomic_notifier_chain_register(&clockset_notifier_list, &xen_clock_was_set);
 
 #ifdef CONFIG_PARAVIRT_CLOCK_VSYSCALL
 	if (xen_setup_vsyscall_timeinfo(cpu) == 0)
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index 5d42d55..422e8ef 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -130,7 +130,7 @@ out_resume:
 	dpm_resume_end(PMSG_RESUME);
 
 	/* Make sure timer events get retriggered on all CPUs */
-	clock_was_set();
+	atomic_notifier_call_chain(&clockset_notifier_list, 0, NULL);
 
 out_thaw:
 #ifdef CONFIG_PREEMPT
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 4759917..c46a4e5 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -247,7 +247,6 @@ static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer)
 #ifdef CONFIG_HIGH_RES_TIMERS
 struct clock_event_device;
 
-extern void clock_was_set(void);
 extern void hres_timers_resume(void);
 extern void hrtimer_interrupt(struct clock_event_device *dev);
 
@@ -282,12 +281,6 @@ extern void hrtimer_peek_ahead_timers(void);
 # define MONOTONIC_RES_NSEC	LOW_RES_NSEC
 # define KTIME_MONOTONIC_RES	KTIME_LOW_RES
 
-/*
- * clock_was_set() is a NOP for non- high-resolution systems. The
- * time-sorted order guarantees that a timer does not expire early and
- * is expired in the next softirq when the clock was advanced.
- */
-static inline void clock_was_set(void) { }
 static inline void hrtimer_peek_ahead_timers(void) { }
 
 static inline void hres_timers_resume(void) { }
diff --git a/include/linux/time.h b/include/linux/time.h
index ea16c1a..5bb7e4a 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -131,6 +131,7 @@ static inline u32 arch_gettimeoffset(void) { return 0; }
 extern void do_gettimeofday(struct timeval *tv);
 extern int do_settimeofday(struct timespec *tv);
 extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
+extern struct atomic_notifier_head clockset_notifier_list;
 #define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
 extern long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags);
 struct itimerval;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 49da79a..c170b65 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -665,7 +665,8 @@ static void retrigger_next_event(void *arg)
  * resolution timer interrupts. On UP we just disable interrupts and
  * call the high resolution interrupt code.
  */
-void clock_was_set(void)
+static int clock_was_set(struct notifier_block *this, unsigned long event,
+		void *ptr)
 {
 	/* Retrigger the CPU local events everywhere */
 	on_each_cpu(retrigger_next_event, NULL, 1);
@@ -772,7 +773,11 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
 }
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { }
 static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { }
-
+static inline int clock_was_set(struct notifier_block *this, unsigned long event,
+		void *ptr)
+{
+	return 0;
+}
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
 #ifdef CONFIG_TIMER_STATS
@@ -1720,11 +1725,16 @@ static struct notifier_block __cpuinitdata hrtimers_nb = {
 	.notifier_call = hrtimer_cpu_notify,
 };
 
+static struct notifier_block hrt_clock_was_set = {
+	.notifier_call  = clock_was_set,
+};
+
 void __init hrtimers_init(void)
 {
 	hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
 			  (void *)(long)smp_processor_id());
 	register_cpu_notifier(&hrtimers_nb);
+	atomic_notifier_chain_register(&clockset_notifier_list, &hrt_clock_was_set);
 #ifdef CONFIG_HIGH_RES_TIMERS
 	open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq);
 #endif
diff --git a/kernel/time.c b/kernel/time.c
index 2951194..667b959 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -138,7 +138,7 @@ static inline void warp_clock(void)
 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
 	update_xtime_cache(0);
 	write_sequnlock_irq(&xtime_lock);
-	clock_was_set();
+	atomic_notifier_call_chain(&clockset_notifier_list, 0, NULL);
 }
 
 /*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e8c77d9..284539f 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -18,7 +18,11 @@
 #include <linux/jiffies.h>
 #include <linux/time.h>
 #include <linux/tick.h>
+#include <linux/notifier.h>
 
+ATOMIC_NOTIFIER_HEAD(clockset_notifier_list);
+
+EXPORT_SYMBOL(clockset_notifier_list);
 
 /*
  * This read-write spinlock protects us from races in SMP while
@@ -174,8 +178,7 @@ int do_settimeofday(struct timespec *tv)
 
 	write_sequnlock_irqrestore(&xtime_lock, flags);
 
-	/* signal hrtimers about time change */
-	clock_was_set();
+	atomic_notifier_call_chain(&clockset_notifier_list, 0, NULL);
 
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2010-02-23 14:25 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-09 18:12 [PATCH] [PVOPS] dom0 sync xen wallclock Stefano Stabellini
2010-02-09 18:20 ` Stefano Stabellini
2010-02-10 23:09 ` Jeremy Fitzhardinge
2010-02-11  0:06   ` Keir Fraser
2010-02-11  0:47     ` Jeremy Fitzhardinge
2010-02-11  8:03       ` Keir Fraser
2010-02-11 19:16         ` Jeremy Fitzhardinge
2010-02-11 11:24   ` Stefano Stabellini
2010-02-11 11:36     ` Ian Campbell
2010-02-18 23:43     ` Jeremy Fitzhardinge
2010-02-19  1:02       ` Dan Magenheimer
2010-02-19  9:10       ` Ian Campbell
2010-02-19  9:39         ` Keir Fraser
2010-02-23 12:13           ` Stefano Stabellini
2010-02-23 14:25           ` Ian Campbell
2010-02-19 23:05         ` Jeremy Fitzhardinge
2010-02-23 14:25           ` Ian Campbell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.