[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] xen/x86: fix for special behavior of first sys_settimeofday(NULL, &tz) invocation
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |