Merge branch 'timers-2038-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Dec 2014 18:13:28 +0000 (10:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Dec 2014 18:13:28 +0000 (10:13 -0800)
Pull more 2038 timer work from Thomas Gleixner:
 "Two more patches for the ongoing 2038 work:

   - New accessors to clock MONOTONIC and REALTIME seconds

  This is a seperate branch as Arnd has follow up work depending on
  this"

* 'timers-2038-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  timekeeping: Provide y2038 safe accessor to the seconds portion of CLOCK_REALTIME
  timekeeping: Provide fast accessor to the seconds part of CLOCK_MONOTONIC

1  2 
include/linux/timekeeping.h
kernel/time/timekeeping.c

index 961fea373f83e8ceb1ef0ec178b4fbe52f5de90f,91454dea2bc6f27aa1b8926364f4434c6b3a4768..9b63d13ba82b3748cc2fd5b61992fde76d8859a2
@@@ -10,7 -10,7 +10,7 @@@ extern int timekeeping_suspended
   * Get and set timeofday
   */
  extern void do_gettimeofday(struct timeval *tv);
 -extern int do_settimeofday(const struct timespec *tv);
 +extern int do_settimeofday64(const struct timespec64 *ts);
  extern int do_sys_settimeofday(const struct timespec *tv,
                               const struct timezone *tz);
  
@@@ -25,22 -25,16 +25,24 @@@ struct timespec __current_kernel_time(v
  /*
   * timespec based interfaces
   */
 -struct timespec get_monotonic_coarse(void);
 -extern void getrawmonotonic(struct timespec *ts);
 +struct timespec64 get_monotonic_coarse64(void);
 +extern void getrawmonotonic64(struct timespec64 *ts);
  extern void ktime_get_ts64(struct timespec64 *ts);
+ extern time64_t ktime_get_seconds(void);
+ extern time64_t ktime_get_real_seconds(void);
  
  extern int __getnstimeofday64(struct timespec64 *tv);
  extern void getnstimeofday64(struct timespec64 *tv);
  
  #if BITS_PER_LONG == 64
 +/**
 + * Deprecated. Use do_settimeofday64().
 + */
 +static inline int do_settimeofday(const struct timespec *ts)
 +{
 +      return do_settimeofday64(ts);
 +}
 +
  static inline int __getnstimeofday(struct timespec *ts)
  {
        return __getnstimeofday64(ts);
@@@ -61,27 -55,7 +63,27 @@@ static inline void ktime_get_real_ts(st
        getnstimeofday64(ts);
  }
  
 +static inline void getrawmonotonic(struct timespec *ts)
 +{
 +      getrawmonotonic64(ts);
 +}
 +
 +static inline struct timespec get_monotonic_coarse(void)
 +{
 +      return get_monotonic_coarse64();
 +}
  #else
 +/**
 + * Deprecated. Use do_settimeofday64().
 + */
 +static inline int do_settimeofday(const struct timespec *ts)
 +{
 +      struct timespec64 ts64;
 +
 +      ts64 = timespec_to_timespec64(*ts);
 +      return do_settimeofday64(&ts64);
 +}
 +
  static inline int __getnstimeofday(struct timespec *ts)
  {
        struct timespec64 ts64;
@@@ -114,19 -88,6 +116,19 @@@ static inline void ktime_get_real_ts(st
        getnstimeofday64(&ts64);
        *ts = timespec64_to_timespec(ts64);
  }
 +
 +static inline void getrawmonotonic(struct timespec *ts)
 +{
 +      struct timespec64 ts64;
 +
 +      getrawmonotonic64(&ts64);
 +      *ts = timespec64_to_timespec(ts64);
 +}
 +
 +static inline struct timespec get_monotonic_coarse(void)
 +{
 +      return timespec64_to_timespec(get_monotonic_coarse64());
 +}
  #endif
  
  extern void getboottime(struct timespec *ts);
@@@ -223,7 -184,7 +225,7 @@@ static inline void timekeeping_clocktai
  /*
   * RTC specific
   */
 -extern void timekeeping_inject_sleeptime(struct timespec *delta);
 +extern void timekeeping_inject_sleeptime64(struct timespec64 *delta);
  
  /*
   * PPS accessor
index 2dc0646258aeebd1102cde4db5bd20162f4d5a4e,0aef92a0a701fde5716e9222f6c1f6db3b14a011..6a931852082f83a0c9c139a0b34d98e3d1483119
@@@ -417,7 -417,8 +417,8 @@@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregist
   */
  static inline void tk_update_ktime_data(struct timekeeper *tk)
  {
-       s64 nsec;
+       u64 seconds;
+       u32 nsec;
  
        /*
         * The xtime based monotonic readout is:
         *      nsec = base_mono + now();
         * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
         */
-       nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
-       nsec *= NSEC_PER_SEC;
-       nsec += tk->wall_to_monotonic.tv_nsec;
-       tk->tkr.base_mono = ns_to_ktime(nsec);
+       seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
+       nsec = (u32) tk->wall_to_monotonic.tv_nsec;
+       tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
  
        /* Update the monotonic raw base */
        tk->base_raw = timespec64_to_ktime(tk->raw_time);
+       /*
+        * The sum of the nanoseconds portions of xtime and
+        * wall_to_monotonic can be greater/equal one second. Take
+        * this into account before updating tk->ktime_sec.
+        */
+       nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
+       if (nsec >= NSEC_PER_SEC)
+               seconds++;
+       tk->ktime_sec = seconds;
  }
  
  /* must hold timekeeper_lock */
@@@ -519,9 -529,9 +529,9 @@@ EXPORT_SYMBOL(__getnstimeofday64)
  
  /**
   * getnstimeofday64 - Returns the time of day in a timespec64.
 - * @ts:               pointer to the timespec to be set
 + * @ts:               pointer to the timespec64 to be set
   *
 - * Returns the time of day in a timespec (WARN if suspended).
 + * Returns the time of day in a timespec64 (WARN if suspended).
   */
  void getnstimeofday64(struct timespec64 *ts)
  {
@@@ -623,7 -633,7 +633,7 @@@ EXPORT_SYMBOL_GPL(ktime_get_raw)
   *
   * The function calculates the monotonic clock from the realtime
   * clock and the wall_to_monotonic offset and stores the result
 - * in normalized timespec format in the variable pointed to by @ts.
 + * in normalized timespec64 format in the variable pointed to by @ts.
   */
  void ktime_get_ts64(struct timespec64 *ts)
  {
  }
  EXPORT_SYMBOL_GPL(ktime_get_ts64);
  
+ /**
+  * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
+  *
+  * Returns the seconds portion of CLOCK_MONOTONIC with a single non
+  * serialized read. tk->ktime_sec is of type 'unsigned long' so this
+  * works on both 32 and 64 bit systems. On 32 bit systems the readout
+  * covers ~136 years of uptime which should be enough to prevent
+  * premature wrap arounds.
+  */
+ time64_t ktime_get_seconds(void)
+ {
+       struct timekeeper *tk = &tk_core.timekeeper;
+       WARN_ON(timekeeping_suspended);
+       return tk->ktime_sec;
+ }
+ EXPORT_SYMBOL_GPL(ktime_get_seconds);
+ /**
+  * ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME
+  *
+  * Returns the wall clock seconds since 1970. This replaces the
+  * get_seconds() interface which is not y2038 safe on 32bit systems.
+  *
+  * For 64bit systems the fast access to tk->xtime_sec is preserved. On
+  * 32bit systems the access must be protected with the sequence
+  * counter to provide "atomic" access to the 64bit tk->xtime_sec
+  * value.
+  */
+ time64_t ktime_get_real_seconds(void)
+ {
+       struct timekeeper *tk = &tk_core.timekeeper;
+       time64_t seconds;
+       unsigned int seq;
+       if (IS_ENABLED(CONFIG_64BIT))
+               return tk->xtime_sec;
+       do {
+               seq = read_seqcount_begin(&tk_core.seq);
+               seconds = tk->xtime_sec;
+       } while (read_seqcount_retry(&tk_core.seq, seq));
+       return seconds;
+ }
+ EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
  #ifdef CONFIG_NTP_PPS
  
  /**
@@@ -703,18 -761,18 +761,18 @@@ void do_gettimeofday(struct timeval *tv
  EXPORT_SYMBOL(do_gettimeofday);
  
  /**
 - * do_settimeofday - Sets the time of day
 - * @tv:               pointer to the timespec variable containing the new time
 + * do_settimeofday64 - Sets the time of day.
 + * @ts:     pointer to the timespec64 variable containing the new time
   *
   * Sets the time of day to the new time and update NTP and notify hrtimers
   */
 -int do_settimeofday(const struct timespec *tv)
 +int do_settimeofday64(const struct timespec64 *ts)
  {
        struct timekeeper *tk = &tk_core.timekeeper;
 -      struct timespec64 ts_delta, xt, tmp;
 +      struct timespec64 ts_delta, xt;
        unsigned long flags;
  
 -      if (!timespec_valid_strict(tv))
 +      if (!timespec64_valid_strict(ts))
                return -EINVAL;
  
        raw_spin_lock_irqsave(&timekeeper_lock, flags);
        timekeeping_forward_now(tk);
  
        xt = tk_xtime(tk);
 -      ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
 -      ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
 +      ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
 +      ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
  
        tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
  
 -      tmp = timespec_to_timespec64(*tv);
 -      tk_set_xtime(tk, &tmp);
 +      tk_set_xtime(tk, ts);
  
        timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
  
  
        return 0;
  }
 -EXPORT_SYMBOL(do_settimeofday);
 +EXPORT_SYMBOL(do_settimeofday64);
  
  /**
   * timekeeping_inject_offset - Adds or subtracts from the current time.
@@@ -894,12 -953,12 +952,12 @@@ int timekeeping_notify(struct clocksour
  }
  
  /**
 - * getrawmonotonic - Returns the raw monotonic time in a timespec
 - * @ts:               pointer to the timespec to be set
 + * getrawmonotonic64 - Returns the raw monotonic time in a timespec
 + * @ts:               pointer to the timespec64 to be set
   *
   * Returns the raw monotonic time (completely un-modified by ntp)
   */
 -void getrawmonotonic(struct timespec *ts)
 +void getrawmonotonic64(struct timespec64 *ts)
  {
        struct timekeeper *tk = &tk_core.timekeeper;
        struct timespec64 ts64;
        } while (read_seqcount_retry(&tk_core.seq, seq));
  
        timespec64_add_ns(&ts64, nsecs);
 -      *ts = timespec64_to_timespec(ts64);
 +      *ts = ts64;
  }
 -EXPORT_SYMBOL(getrawmonotonic);
 +EXPORT_SYMBOL(getrawmonotonic64);
 +
  
  /**
   * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
@@@ -1068,8 -1126,8 +1126,8 @@@ static void __timekeeping_inject_sleept
  }
  
  /**
 - * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
 - * @delta: pointer to a timespec delta value
 + * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values
 + * @delta: pointer to a timespec64 delta value
   *
   * This hook is for architectures that cannot support read_persistent_clock
   * because their RTC/persistent clock is only accessible when irqs are enabled.
   * This function should only be called by rtc_resume(), and allows
   * a suspend offset to be injected into the timekeeping values.
   */
 -void timekeeping_inject_sleeptime(struct timespec *delta)
 +void timekeeping_inject_sleeptime64(struct timespec64 *delta)
  {
        struct timekeeper *tk = &tk_core.timekeeper;
 -      struct timespec64 tmp;
        unsigned long flags;
  
        /*
  
        timekeeping_forward_now(tk);
  
 -      tmp = timespec_to_timespec64(*delta);
 -      __timekeeping_inject_sleeptime(tk, &tmp);
 +      __timekeeping_inject_sleeptime(tk, delta);
  
        timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
  
@@@ -1330,12 -1390,6 +1388,12 @@@ static __always_inline void timekeeping
         *
         * XXX - TODO: Doc ntp_error calculation.
         */
 +      if ((mult_adj > 0) && (tk->tkr.mult + mult_adj < mult_adj)) {
 +              /* NTP adjustment caused clocksource mult overflow */
 +              WARN_ON_ONCE(1);
 +              return;
 +      }
 +
        tk->tkr.mult += mult_adj;
        tk->xtime_interval += interval;
        tk->tkr.xtime_nsec -= offset;
@@@ -1401,8 -1455,7 +1459,8 @@@ static void timekeeping_adjust(struct t
        }
  
        if (unlikely(tk->tkr.clock->maxadj &&
 -              (tk->tkr.mult > tk->tkr.clock->mult + tk->tkr.clock->maxadj))) {
 +              (abs(tk->tkr.mult - tk->tkr.clock->mult)
 +                      > tk->tkr.clock->maxadj))) {
                printk_once(KERN_WARNING
                        "Adjusting %s more than 11%% (%ld vs %ld)\n",
                        tk->tkr.clock->name, (long)tk->tkr.mult,
@@@ -1651,7 -1704,7 +1709,7 @@@ struct timespec current_kernel_time(voi
  }
  EXPORT_SYMBOL(current_kernel_time);
  
 -struct timespec get_monotonic_coarse(void)
 +struct timespec64 get_monotonic_coarse64(void)
  {
        struct timekeeper *tk = &tk_core.timekeeper;
        struct timespec64 now, mono;
        set_normalized_timespec64(&now, now.tv_sec + mono.tv_sec,
                                now.tv_nsec + mono.tv_nsec);
  
 -      return timespec64_to_timespec(now);
 +      return now;
  }
  
  /*