aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-16 15:40:43 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-16 15:40:43 +0000
commiteb72f656ae6128891e67422d68ef132bc70393ac (patch)
tree7833f598bcc020478a89b5d2bc8a76e2d4b2921a
parentf31042c4c4a2f0a429a0471a16e3b25139b657df (diff)
downloadxen-eb72f656ae6128891e67422d68ef132bc70393ac.tar.gz
xen-eb72f656ae6128891e67422d68ef132bc70393ac.tar.bz2
xen-eb72f656ae6128891e67422d68ef132bc70393ac.zip
Fix xtime_lock handling in timer interrupt. There's no need
to hold it while doing local VCPU work, and there might be danger of deadlock if we do. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c45
1 files changed, 15 insertions, 30 deletions
diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
index ea421f080b..4ceded947a 100644
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
@@ -540,17 +540,14 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
#endif
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void do_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
s64 delta, delta_cpu;
int cpu = smp_processor_id();
struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
+ write_seqlock(&xtime_lock);
+
do {
get_time_values_from_xen();
@@ -582,7 +579,18 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
do_timer(regs);
}
- /* Local CPU jiffy work. */
+ if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
+ update_wallclock();
+ clock_was_set();
+ }
+
+ write_sequnlock(&xtime_lock);
+
+ /*
+ * Local CPU jiffy work. No need to hold xtime_lock, and I'm not sure
+ * if there is risk of deadlock if we do (since update_process_times
+ * may do scheduler rebalancing work and thus acquire runqueue locks).
+ */
while (delta_cpu >= NS_PER_TICK) {
delta_cpu -= NS_PER_TICK;
per_cpu(processed_system_time, cpu) += NS_PER_TICK;
@@ -590,29 +598,6 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
profile_tick(CPU_PROFILING, regs);
}
- if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
- update_wallclock();
- clock_was_set();
- }
-}
-
-/*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
- */
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- /*
- * Here we are in the timer irq handler. We just have irqs locally
- * disabled but we don't know if the timer_bh is running on the other
- * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
- * the irq version of write_lock because as just said we have irq
- * locally disabled. -arca
- */
- write_seqlock(&xtime_lock);
- do_timer_interrupt(irq, NULL, regs);
- write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}