Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > d0a35cd31c1125e2132804d68547073d > files > 4661

kernel-2.6.18-194.26.1.el5.src.rpm

From: Rik van Riel <riel@redhat.com>
Date: Mon, 13 Apr 2009 12:07:22 -0400
Subject: [xen] x86: misc fixes to the timer code
Message-id: 20090413120722.1a2455c1@bree.surriel.com
O-Subject: [RHEL 5.4 PATCH 2/5] misc fixes to the timer code (bz 449346)
Bugzilla: 449346
RH-Acked-by: Justin M. Forbes <jforbes@redhat.com>
RH-Acked-by: Chris Lalancette <clalance@redhat.com>
RH-Acked-by: Don Dutile <ddutile@redhat.com>

More fixes to the timer infrastructure, required for correct
HVM timekeeping.

Fixes bug 449346

# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1197470499 0
# Node ID 03551b644e35dbec62d657e6f943faa5dd310409
# Parent  1caed71f2a357533a569a7fdac7bfb06ca2368a7
[HVM] Don't count "missed ticks" on one-shot timers.
It's not clear what it would mean, and it leads to division by zero.
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen-unstable changeset:   15943:c0d1825f51899b329495efb2078dd15e0fb3b479
xen-unstable date:        Mon Sep 24 13:44:29 2007 +0100

hvm: Fix one-shot timers. Do not disable until the interrupt has been
latched by the target VCPU.
Signed-off-by: Keir Fraser <keir@xensource.com>
xen-unstable changeset:   16125:b4278beaf3549f410a5a6086dbd8af93c495aeac
xen-unstable date:        Wed Oct 17 13:12:03 2007 +0100

hvm: Fix destroy_periodic_time() to not race destruction of one-shot
timers.

This bug was tracked down by Dexuan Cui <dexuan.cui@intel.com>

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen-unstable changeset:   16595:f2f7c92bf1c15206aa7072f6a4e470a132d528e2
xen-unstable date:        Wed Dec 12 11:08:21 2007 +0000

diff --git a/arch/x86/hvm/vioapic.c b/arch/x86/hvm/vioapic.c
index 3266c39..c86cbfa 100644
--- a/arch/x86/hvm/vioapic.c
+++ b/arch/x86/hvm/vioapic.c
@@ -311,7 +311,7 @@ static inline int pit_channel0_enabled(void)
 {
     PITState *pit = &current->domain->arch.hvm_domain.pl_time.vpit;
     struct periodic_time *pt = &pit->pt[0];
-    return pt->enabled;
+    return pt_active(pt);
 }
 
 static void vioapic_deliver(struct hvm_hw_vioapic *vioapic, int irq)
diff --git a/arch/x86/hvm/vlapic.c b/arch/x86/hvm/vlapic.c
index 38dd9e9..f4b3b8d 100644
--- a/arch/x86/hvm/vlapic.c
+++ b/arch/x86/hvm/vlapic.c
@@ -956,15 +956,12 @@ void vlapic_destroy(struct vcpu *v)
 
 int is_lvtt(struct vcpu *v, int vector)
 {
-    return vcpu_vlapic(v)->pt.enabled &&
-           vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT);
+    return (pt_active(&vcpu_vlapic(v)->pt) &&
+            (vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT)));
 }
 
 int is_lvtt_enabled(struct vcpu *v)
 {
-    if ( unlikely(!vlapic_enabled(vcpu_vlapic(v))) ||
-            !vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT)) 
-        return 0;
-
-    return 1;
+    return (vlapic_enabled(vcpu_vlapic(v)) &&
+            vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT));
 }
diff --git a/arch/x86/hvm/vpt.c b/arch/x86/hvm/vpt.c
index 4762ef6..18dc6ee 100644
--- a/arch/x86/hvm/vpt.c
+++ b/arch/x86/hvm/vpt.c
@@ -114,12 +114,13 @@ static void pt_timer_fn(void *data)
     pt_lock(pt);
 
     pt->pending_intr_nr++;
-    pt->scheduled += pt->period;
-
-    missed_ticks(pt);
 
     if ( !pt->one_shot )
+    {
+        pt->scheduled += pt->period;
+        missed_ticks(pt);
         set_timer(&pt->timer, pt->scheduled);
+    }
 
     vcpu_kick(pt->vcpu);
 
@@ -204,10 +205,17 @@ void pt_intr_post(struct vcpu *v, int vector, int type)
         return;
     }
 
-    ASSERT(pt->vcpu == v);
-
-    pt->pending_intr_nr--;
-    pt->last_plt_gtime += pt->period_cycles;
+    if ( pt->one_shot )
+    {
+        if ( pt->on_list )
+            list_del(&pt->list);
+        pt->on_list = 0;
+    }
+    else
+    {
+        pt->pending_intr_nr--;
+        pt->last_plt_gtime += pt->period_cycles;
+    }
 
     if ( hvm_get_guest_time(v) < pt->last_plt_gtime )
         hvm_set_guest_time(v, pt->last_plt_gtime);
@@ -260,7 +268,6 @@ void create_periodic_time(
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
-    pt->enabled = 1;
     pt->pending_intr_nr = 0;
 
     /* Periodic timer must be at least 0.9ms. */
@@ -282,6 +289,7 @@ void create_periodic_time(
     pt->cb = cb;
     pt->priv = data;
 
+    pt->on_list = 1;
     list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
 
     init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
@@ -292,12 +300,14 @@ void create_periodic_time(
 
 void destroy_periodic_time(struct periodic_time *pt)
 {
-    if ( !pt->enabled )
+    /* Was this structure previously initialised by create_periodic_time()? */
+    if ( pt->vcpu == NULL )
         return;
 
     pt_lock(pt);
-    pt->enabled = 0;
-    list_del(&pt->list);
+    if ( pt->on_list )
+        list_del(&pt->list);
+    pt->on_list = 0;
     pt_unlock(pt);
 
     /*
diff --git a/include/asm-x86/hvm/vpt.h b/include/asm-x86/hvm/vpt.h
index acd245a..20e4fbb 100644
--- a/include/asm-x86/hvm/vpt.h
+++ b/include/asm-x86/hvm/vpt.h
@@ -55,11 +55,11 @@ typedef void time_cb(struct vcpu *v, void *opaque);
 
 struct periodic_time {
     struct list_head list;
-    char enabled;
-    char one_shot;              /* one shot time */
+    bool_t on_list;
+    bool_t one_shot;
     u8 irq;
     struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
-    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
+    u32 pending_intr_nr;        /* pending timer interrupts */
     u64 period;                 /* frequency in ns */
     u64 period_cycles;          /* frequency in cpu cycles */
     s_time_t scheduled;         /* scheduled timer interrupt */
@@ -122,6 +122,17 @@ void pt_update_irq(struct vcpu *v);
 void pt_intr_post(struct vcpu *v, int vector, int type);
 void pt_reset(struct vcpu *v);
 void pt_migrate(struct vcpu *v);
+
+/* Is given periodic timer active? */
+#define pt_active(pt) ((pt)->on_list)
+
+/*
+ * Create/destroy a periodic (or one-shot!) timer.
+ * The given periodic timer structure must be initialised with zero bytes or
+ * have been initialised by a previous invocation of create_periodic_time().
+ * Note that, for a given periodic timer, invocations of these functions MUST
+ * be serialised.
+ */
 void create_periodic_time(
     struct vcpu *v, struct periodic_time *pt, uint64_t period,
     uint8_t irq, char one_shot, time_cb *cb, void *data);