Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3962

kernel-2.6.18-194.11.1.el5.src.rpm

From: Glauber Costa <glommer@redhat.com>
Date: Fri, 18 Sep 2009 17:27:22 -0400
Subject: [x86] kvm: fix vsyscall going backwards
Message-id: 1253309243-13769-2-git-send-email-glommer@redhat.com
O-Subject: [PATCH 1/2] RHEL5 BZ524076 fix vsyscall going backwards
Bugzilla: 524076
RH-Acked-by: Rik van Riel <riel@redhat.com>

When using vsyscall infrastructure, clock can go backwards. This is because
kvmclock relies on tsc, but not entirely, so the checks in VXTIME_TSC
are not enough.

This patch provides VXTIME_KVM, and uses the value stored in vxtime.last_kvm
as a lower bound. We won't allow clock to go lower than this value.

This mechanism is also implemented for the monotonic clock, that theorectically
suffered from the same problem

RH-Upstream-status: Specific to RHEL5 port.

Signed-off-by: Glauber Costa <glommer@redhat.com>

diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 13e002f..90bc1e7 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -313,7 +313,16 @@ unsigned long long monotonic_clock(void)
  	u32 last_offset, this_offset, offset;
 	unsigned long long base;
 
-	if (vxtime.mode == VXTIME_HPET) {
+	if (vxtime.mode == VXTIME_KVM) {
+		do {
+			seq = read_seqbegin(&xtime_lock);
+
+			last_offset = vxtime.last_kvm;
+			base = monotonic_base;
+			this_offset = kvm_clock_read();
+		} while (read_seqretry(&xtime_lock, seq));
+		offset = (this_offset - last_offset);
+	} else if (vxtime.mode == VXTIME_HPET) {
 		do {
 			seq = read_seqbegin(&xtime_lock);
 
@@ -1199,7 +1208,7 @@ void time_init_gtod(void)
 	if (use_kvm_time) {
 		timetype = "KVM";
 		vxtime.last_kvm = kvm_clock_read();
-		vxtime.mode = VXTIME_TSC;
+		vxtime.mode = VXTIME_KVM;
 		do_gettimeoffset = do_gettimeoffset_kvm;
 	} else if (timekeeping_use_tsc > 0) {
 		timetype = "TSC Timekeeping";
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 69719d6..b511d73 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -76,8 +76,16 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
 		sec = __xtime.tv_sec;
 		nsec = __xtime.tv_nsec +
 			(__jiffies - __wall_jiffies) * (NSEC_PER_SEC / HZ);
+		if (__vxtime.mode == VXTIME_KVM) {
+			long delta;
+			t = get_cycles_sync();
+			if (t < __vxtime.last_tsc)
+				t = __vxtime.last_tsc;
 
-		if (__vxtime.mode != VXTIME_HPET) {
+			delta = ((t * __vxtime.tsc_quot) >> NS_SCALE) - __vxtime.last_kvm;
+			if (delta > 0)
+				nsec += delta;
+		} else if (__vxtime.mode != VXTIME_HPET) {
 			t = get_cycles_sync();
 			if (t < __vxtime.last_tsc)
 				t = __vxtime.last_tsc;
diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
index 53c1fe9..dd90792 100644
--- a/include/asm-x86_64/vsyscall.h
+++ b/include/asm-x86_64/vsyscall.h
@@ -27,6 +27,7 @@ enum vsyscall_num {
 #define VXTIME_TSC	1
 #define VXTIME_HPET	2
 #define VXTIME_PMTMR	3
+#define VXTIME_KVM	4
 
 #define VGETCPU_RDTSCP	1
 #define VGETCPU_LSL	2