summaryrefslogtreecommitdiff
blob: bd70c35633c62ce9013b59fd09c9b598d01b46f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# HG changeset 81 patch
# User Ian Campbell <ian.campbell@xensource.com>
# Date 1183393164 -3600
# Node ID cb040341e05af32c804afef4216ec5491dcbf9e3
# Parent  4a284f968015fa4cd50d9d4c7695534c87c7bce6
Subject: Do not call clock_was_set() from interrupt context.

Currently clock_was_set() is a nop but on newer kernels it is not and
cannot be called from interrupt context. Prepare for that by deferring
to a workqueue. Since a timer interrupt can occur before
init_workqueue() is called we need to protect against the possibility
that keventd hasn't started yet.

(drop unused variable max_ntp_tick).

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>

Acked-by: jbeulich@novell.com

---
 arch/i386/kernel/time-xen.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

--- a/arch/i386/kernel/time-xen.c	2007-08-27 14:01:25.000000000 -0400
+++ b/arch/i386/kernel/time-xen.c	2007-08-27 14:02:04.000000000 -0400
@@ -127,6 +127,12 @@ static DEFINE_PER_CPU(struct vcpu_runsta
 /* Must be signed, as it's compared with s64 quantities which can be -ve. */
 #define NS_PER_TICK (1000000000LL/HZ)
 
+static void __clock_was_set(void *unused)
+{
+	clock_was_set();
+}
+static DECLARE_WORK(clock_was_set_work, __clock_was_set, NULL);
+
 static inline void __normalize_time(time_t *sec, s64 *nsec)
 {
 	while (*nsec >= NSEC_PER_SEC) {
@@ -667,7 +673,8 @@ irqreturn_t timer_interrupt(int irq, voi
 
 	if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
 		update_wallclock();
-		clock_was_set();
+		if (keventd_up())
+			schedule_work(&clock_was_set_work);
 	}
 
 	write_sequnlock(&xtime_lock);