# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1276866717 -3600
# Node ID 7b350604ce957e12146afc432c37c81c0b75e8fc
# Parent a24d8631a0007dcb31b128452c6162ea796b05aa
xen/x86: fix for special behavior of first sys_settimeofday(NULL, &tz)
invocation
The data Xen's time implementation maintains to make do_gettimeofday()
return values monotonic needs to be reset not only during normal
do_gettimeofday() invocations, but also when the clock gets warped
due to the hardware (CMOS) clock running on local (rather than UTC)
time.
Additionally there was a time window in do_gettimeofday() (between
the end of the xtime read loop and the acquiring of the monotonicity
data lock) where, if on another processor do_settimeofday() would
execute to completion, the zeroes written by the latter could get
overwritten by the former with values obtained before the time was
updated. This now gets prevented by maintaining a version for the
monotonicity data.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
arch/i386/kernel/time-xen.c | 55 ++++++++++++++++++++++++++++----------------
kernel/time.c | 3 ++
2 files changed, 38 insertions(+), 20 deletions(-)
diff -r a24d8631a000 -r 7b350604ce95 arch/i386/kernel/time-xen.c
--- a/arch/i386/kernel/time-xen.c Fri Jun 11 09:37:25 2010 +0100
+++ b/arch/i386/kernel/time-xen.c Fri Jun 18 14:11:57 2010 +0100
@@ -114,9 +114,6 @@ static struct timespec shadow_tv;
static struct timespec shadow_tv;
static u32 shadow_tv_version;
-static struct timeval monotonic_tv;
-static spinlock_t monotonic_lock = SPIN_LOCK_UNLOCKED;
-
/* Keep track of last time we did processing/updating of jiffies and xtime. */
static u64 processed_system_time; /* System time (ns) at last processing. */
static DEFINE_PER_CPU(u64, processed_system_time);
@@ -377,6 +374,12 @@ void rtc_cmos_write(unsigned char val, u
}
EXPORT_SYMBOL(rtc_cmos_write);
+static struct {
+ spinlock_t lock;
+ struct timeval tv;
+ u32 version;
+} monotonic = { .lock = SPIN_LOCK_UNLOCKED };
+
/*
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
@@ -389,7 +392,7 @@ void do_gettimeofday(struct timeval *tv)
s64 nsec;
unsigned int cpu;
struct shadow_time_info *shadow;
- u32 local_time_version;
+ u32 local_time_version, monotonic_version;
cpu = get_cpu();
shadow = &per_cpu(shadow_time, cpu);
@@ -412,6 +415,8 @@ void do_gettimeofday(struct timeval *tv)
nsec = shadow->system_timestamp - processed_system_time;
__normalize_time(&sec, &nsec);
usec += (long)nsec / NSEC_PER_USEC;
+
+ monotonic_version = monotonic.version;
if (unlikely(!time_values_up_to_date(cpu))) {
/*
@@ -434,23 +439,32 @@ void do_gettimeofday(struct timeval *tv)
sec++;
}
- spin_lock_irqsave(&monotonic_lock, flags);
- if ((sec > monotonic_tv.tv_sec) ||
- ((sec == monotonic_tv.tv_sec) && (usec > monotonic_tv.tv_usec)))
- {
- monotonic_tv.tv_sec = sec;
- monotonic_tv.tv_usec = usec;
- } else {
- sec = monotonic_tv.tv_sec;
- usec = monotonic_tv.tv_usec;
- }
- spin_unlock_irqrestore(&monotonic_lock, flags);
+ spin_lock_irqsave(&monotonic.lock, flags);
+ if (unlikely(sec < monotonic.tv.tv_sec) ||
+ (sec == monotonic.tv.tv_sec && usec <= monotonic.tv.tv_usec)) {
+ sec = monotonic.tv.tv_sec;
+ usec = monotonic.tv.tv_usec;
+ } else if (likely(monotonic_version == monotonic.version)) {
+ monotonic.tv.tv_sec = sec;
+ monotonic.tv.tv_usec = usec;
+ }
+ spin_unlock_irqrestore(&monotonic.lock, flags);
tv->tv_sec = sec;
tv->tv_usec = usec;
}
EXPORT_SYMBOL(do_gettimeofday);
+
+/* Reset monotonic gettimeofday() timeval. */
+static inline void monotonic_reset(void)
+{
+ spin_lock(&monotonic.lock);
+ monotonic.tv.tv_sec = 0;
+ monotonic.tv.tv_usec = 0;
+ ++monotonic.version;
+ spin_unlock(&monotonic.lock);
+}
int do_settimeofday(struct timespec *tv)
{
@@ -459,6 +473,11 @@ int do_settimeofday(struct timespec *tv)
unsigned int cpu;
struct shadow_time_info *shadow;
struct xen_platform_op op;
+
+ if (unlikely(!tv)) {
+ monotonic_reset();
+ return 0;
+ }
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
@@ -499,11 +518,7 @@ int do_settimeofday(struct timespec *tv)
}
ntp_clear();
- /* Reset monotonic gettimeofday() timeval. */
- spin_lock(&monotonic_lock);
- monotonic_tv.tv_sec = 0;
- monotonic_tv.tv_usec = 0;
- spin_unlock(&monotonic_lock);
+ monotonic_reset();
write_sequnlock_irq(&xtime_lock);
diff -r a24d8631a000 -r 7b350604ce95 kernel/time.c
--- a/kernel/time.c Fri Jun 11 09:37:25 2010 +0100
+++ b/kernel/time.c Fri Jun 18 14:11:57 2010 +0100
@@ -135,6 +135,9 @@ static inline void warp_clock(void)
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
time_interpolator_reset();
+#if defined(CONFIG_XEN) && defined(CONFIG_X86)
+ do_settimeofday(NULL);
+#endif
write_sequnlock_irq(&xtime_lock);
clock_was_set();
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|