diff options
| -rw-r--r-- | kernel/time.c | 32 | 
1 files changed, 24 insertions, 8 deletions
diff --git a/kernel/time.c b/kernel/time.c index f04791f6940..ffe19149d77 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -57,14 +57,17 @@ EXPORT_SYMBOL(sys_tz);   */  asmlinkage long sys_time(time_t __user * tloc)  { -	time_t i; -	struct timeval tv; +	/* +	 * We read xtime.tv_sec atomically - it's updated +	 * atomically by update_wall_time(), so no need to +	 * even read-lock the xtime seqlock: +	 */ +	time_t i = xtime.tv_sec; -	do_gettimeofday(&tv); -	i = tv.tv_sec; +	smp_rmb(); /* sys_time() results are coherent */  	if (tloc) { -		if (put_user(i,tloc)) +		if (put_user(i, tloc))  			i = -EFAULT;  	}  	return i; @@ -373,12 +376,25 @@ void do_gettimeofday (struct timeval *tv)  	tv->tv_sec = sec;  	tv->tv_usec = usec; -} +	/* +	 * Make sure xtime.tv_sec [returned by sys_time()] always +	 * follows the gettimeofday() result precisely. This +	 * condition is extremely unlikely, it can hit at most +	 * once per second: +	 */ +	if (unlikely(xtime.tv_sec != tv->tv_sec)) { +		unsigned long flags; + +		write_seqlock_irqsave(&xtime_lock, flags); +		update_wall_time(); +		write_sequnlock_irqrestore(&xtime_lock, flags); +	} +}  EXPORT_SYMBOL(do_gettimeofday); +#else	/* CONFIG_TIME_INTERPOLATION */ -#else  #ifndef CONFIG_GENERIC_TIME  /*   * Simulate gettimeofday using do_gettimeofday which only allows a timeval @@ -394,7 +410,7 @@ void getnstimeofday(struct timespec *tv)  }  EXPORT_SYMBOL_GPL(getnstimeofday);  #endif -#endif +#endif	/* CONFIG_TIME_INTERPOLATION */  /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.   * Assumes input in normal date format, i.e. 1980-12-31 23:59:59  |