Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1471

kernel-2.6.18-238.el5.src.rpm

From: Prarit Bhargava <prarit@redhat.com>
Date: Mon, 11 May 2009 10:01:41 -0400
Subject: [ia64] fix regression in nanosleep syscall
Message-id: 20090511140138.10014.34992.sendpatchset@prarit.bos.redhat.com
O-Subject: [RHEL5 PATCH]: ia64 - fix regression in nanosleep() syscall
Bugzilla: 499289
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>
RH-Acked-by: Brian Maly <bmaly@redhat.com>

After applying the fix for BZ 485323, a regression in the behavior of
nanosleep was noted -- occasionally nanosleep would sleep slightly less than
the requested time on ia64.

The following patch resolves the situation.  It does, however, have a drawback.
On systems using time interpolation, when a timer interrupt occurs and an
hrtimer is active there will be an additional delay due to the calling of
gettimeofday().  I've minimized the impact (obvious patch chunk below) by
only calling getnstimeofday() when timer interpolation is configured and used
within the kernel.

Compiled and tested successfully on a few ia64 systems listed in the BZ.
Testing was done using the test in 499289 and the test from 485323.  No
failures were seen for either test in 18+ hours of testing on three
different vendor's systems.

Resolves BZ 499289.

diff --git a/include/linux/timex.h b/include/linux/timex.h
index ab71c9a..46c8c3f 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -294,6 +294,7 @@ extern void register_time_interpolator(struct time_interpolator *);
 extern void unregister_time_interpolator(struct time_interpolator *);
 extern void time_interpolator_reset(void);
 extern unsigned long time_interpolator_get_offset(void);
+extern struct time_interpolator *time_interpolator;
 
 #else /* !CONFIG_TIME_INTERPOLATION */
 
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 6088238..8904a61 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -37,6 +37,7 @@
 #include <linux/notifier.h>
 #include <linux/syscalls.h>
 #include <linux/interrupt.h>
+#include <linux/timex.h>
 
 #include <asm/uaccess.h>
 
@@ -63,11 +64,7 @@ static ktime_t ktime_get_real(void)
 {
 	struct timespec now;
 
-#ifdef CONFIG_TIME_INTERPOLATION
-	now = current_kernel_time();
-#else
 	getnstimeofday(&now);
-#endif
 
 	return timespec_to_ktime(now);
 }
@@ -115,11 +112,7 @@ void ktime_get_ts(struct timespec *ts)
 
 	do {
 		seq = read_seqbegin(&xtime_lock);
-#ifdef CONFIG_TIME_INTERPOLATION
-		*ts = xtime;
-#else
 		getnstimeofday(ts);
-#endif
 		tomono = wall_to_monotonic;
 
 	} while (read_seqretry(&xtime_lock, seq));
@@ -137,10 +130,20 @@ static void hrtimer_get_softirq_time(struct hrtimer_base *base)
 {
 	ktime_t xtim, tomono;
 	unsigned long seq;
+	struct timespec ts;
 
 	do {
 		seq = read_seqbegin(&xtime_lock);
-		xtim = timespec_to_ktime(xtime);
+#ifdef CONFIG_TIME_INTERPOLATION
+		if (time_interpolator) {
+			getnstimeofday(&ts);
+			xtim = timespec_to_ktime(ts);
+		} else {
+			xtim = timespec_to_ktime(xtime);
+		}
+#else
+ 		xtim = timespec_to_ktime(xtime);
+#endif
 		tomono = timespec_to_ktime(wall_to_monotonic);
 
 	} while (read_seqretry(&xtime_lock, seq));