timekeeping: Consolidate timekeeping_inject_offset code
authorArnd Bergmann <arnd@arndb.de>
Thu, 19 Oct 2017 11:14:44 +0000 (13:14 +0200)
committerJohn Stultz <john.stultz@linaro.org>
Mon, 30 Oct 2017 22:13:35 +0000 (15:13 -0700)
The code to check the adjtimex() or clock_adjtime() arguments is spread
out across multiple files for presumably only historic reasons. As a
preparatation for a rework to get rid of the use of 'struct timeval'
and 'struct timespec' in there, this moves all the portions into
kernel/time/timekeeping.c and marks them as 'static'.

The warp_clock() function here is not as closely related as the others,
but I feel it still makes sense to move it here in order to consolidate
all callers of timekeeping_inject_offset().

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Miroslav Lichvar <mlichvar@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Stephen Boyd <stephen.boyd@linaro.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
[jstultz: Whitespace fixup]
Signed-off-by: John Stultz <john.stultz@linaro.org>
include/linux/time.h
kernel/time/ntp.c
kernel/time/ntp_internal.h
kernel/time/time.c
kernel/time/timekeeping.c
kernel/time/timekeeping.h

index 9bc1f94..c0fbad0 100644 (file)
@@ -134,32 +134,6 @@ static inline bool timeval_valid(const struct timeval *tv)
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
-/*
- * Validates if a timespec/timeval used to inject a time offset is valid.
- * Offsets can be postive or negative. The value of the timeval/timespec
- * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
- * always be non-negative.
- */
-static inline bool timeval_inject_offset_valid(const struct timeval *tv)
-{
-       /* We don't check the tv_sec as it can be positive or negative */
-
-       /* Can't have more microseconds then a second */
-       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
-               return false;
-       return true;
-}
-
-static inline bool timespec_inject_offset_valid(const struct timespec *ts)
-{
-       /* We don't check the tv_sec as it can be positive or negative */
-
-       /* Can't have more nanoseconds then a second */
-       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
-               return false;
-       return true;
-}
-
 /* Some architectures do not supply their own clocksource.
  * This is mainly the case in architectures that get their
  * inter-tick times by reading the counter on their interval
index bc19de1..90f8458 100644 (file)
@@ -713,67 +713,6 @@ static inline void process_adjtimex_modes(struct timex *txc,
 }
 
 
-
-/**
- * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex
- */
-int ntp_validate_timex(struct timex *txc)
-{
-       if (txc->modes & ADJ_ADJTIME) {
-               /* singleshot must not be used with any other mode bits */
-               if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
-                       return -EINVAL;
-               if (!(txc->modes & ADJ_OFFSET_READONLY) &&
-                   !capable(CAP_SYS_TIME))
-                       return -EPERM;
-       } else {
-               /* In order to modify anything, you gotta be super-user! */
-                if (txc->modes && !capable(CAP_SYS_TIME))
-                       return -EPERM;
-               /*
-                * if the quartz is off by more than 10% then
-                * something is VERY wrong!
-                */
-               if (txc->modes & ADJ_TICK &&
-                   (txc->tick <  900000/USER_HZ ||
-                    txc->tick > 1100000/USER_HZ))
-                       return -EINVAL;
-       }
-
-       if (txc->modes & ADJ_SETOFFSET) {
-               /* In order to inject time, you gotta be super-user! */
-               if (!capable(CAP_SYS_TIME))
-                       return -EPERM;
-
-               if (txc->modes & ADJ_NANO) {
-                       struct timespec ts;
-
-                       ts.tv_sec = txc->time.tv_sec;
-                       ts.tv_nsec = txc->time.tv_usec;
-                       if (!timespec_inject_offset_valid(&ts))
-                               return -EINVAL;
-
-               } else {
-                       if (!timeval_inject_offset_valid(&txc->time))
-                               return -EINVAL;
-               }
-       }
-
-       /*
-        * Check for potential multiplication overflows that can
-        * only happen on 64-bit systems:
-        */
-       if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) {
-               if (LLONG_MIN / PPM_SCALE > txc->freq)
-                       return -EINVAL;
-               if (LLONG_MAX / PPM_SCALE < txc->freq)
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-
 /*
  * adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
index d8a7c11..74b52cd 100644 (file)
@@ -7,7 +7,6 @@ extern void ntp_clear(void);
 extern u64 ntp_tick_length(void);
 extern ktime_t ntp_get_next_leap(void);
 extern int second_overflow(time64_t secs);
-extern int ntp_validate_timex(struct timex *);
 extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
 extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
 #endif /* _LINUX_NTP_INTERNAL_H */
index 44a8c14..04684e2 100644 (file)
@@ -158,40 +158,6 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
 }
 
 /*
- * Indicates if there is an offset between the system clock and the hardware
- * clock/persistent clock/rtc.
- */
-int persistent_clock_is_local;
-
-/*
- * Adjust the time obtained from the CMOS to be UTC time instead of
- * local time.
- *
- * This is ugly, but preferable to the alternatives.  Otherwise we
- * would either need to write a program to do it in /etc/rc (and risk
- * confusion if the program gets run more than once; it would also be
- * hard to make the program warp the clock precisely n hours)  or
- * compile in the timezone information into the kernel.  Bad, bad....
- *
- *                                             - TYT, 1992-01-01
- *
- * The best thing to do is to keep the CMOS clock in universal time (UTC)
- * as real UNIX machines always do it. This avoids all headaches about
- * daylight saving times and warping kernel clocks.
- */
-static inline void warp_clock(void)
-{
-       if (sys_tz.tz_minuteswest != 0) {
-               struct timespec adjust;
-
-               persistent_clock_is_local = 1;
-               adjust.tv_sec = sys_tz.tz_minuteswest * 60;
-               adjust.tv_nsec = 0;
-               timekeeping_inject_offset(&adjust);
-       }
-}
-
-/*
  * In case for some reason the CMOS clock has not already been running
  * in UTC, but in some local time: The first time we set the timezone,
  * we will warp the clock so that it is ticking UTC time instead of
@@ -224,7 +190,7 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz
                if (firsttime) {
                        firsttime = 0;
                        if (!tv)
-                               warp_clock();
+                               timekeeping_warp_clock();
                }
        }
        if (tv)
index 2cafb49..7d8e0e8 100644 (file)
@@ -1258,13 +1258,39 @@ out:
 }
 EXPORT_SYMBOL(do_settimeofday64);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+       return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more nanoseconds then a second */
+       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+               return false;
+       return true;
+}
+
 /**
  * timekeeping_inject_offset - Adds or subtracts from the current time.
  * @tv:                pointer to the timespec variable containing the offset
  *
  * Adds or subtracts an offset value from the current time.
  */
-int timekeeping_inject_offset(struct timespec *ts)
+static int timekeeping_inject_offset(struct timespec *ts)
 {
        struct timekeeper *tk = &tk_core.timekeeper;
        unsigned long flags;
@@ -1303,7 +1329,40 @@ error: /* even if we error out, we forwarded the time, so call update */
 
        return ret;
 }
-EXPORT_SYMBOL(timekeeping_inject_offset);
+
+/*
+ * Indicates if there is an offset between the system clock and the hardware
+ * clock/persistent clock/rtc.
+ */
+int persistent_clock_is_local;
+
+/*
+ * Adjust the time obtained from the CMOS to be UTC time instead of
+ * local time.
+ *
+ * This is ugly, but preferable to the alternatives.  Otherwise we
+ * would either need to write a program to do it in /etc/rc (and risk
+ * confusion if the program gets run more than once; it would also be
+ * hard to make the program warp the clock precisely n hours)  or
+ * compile in the timezone information into the kernel.  Bad, bad....
+ *
+ *                                             - TYT, 1992-01-01
+ *
+ * The best thing to do is to keep the CMOS clock in universal time (UTC)
+ * as real UNIX machines always do it. This avoids all headaches about
+ * daylight saving times and warping kernel clocks.
+ */
+void timekeeping_warp_clock(void)
+{
+       if (sys_tz.tz_minuteswest != 0) {
+               struct timespec adjust;
+
+               persistent_clock_is_local = 1;
+               adjust.tv_sec = sys_tz.tz_minuteswest * 60;
+               adjust.tv_nsec = 0;
+               timekeeping_inject_offset(&adjust);
+       }
+}
 
 /**
  * __timekeeping_set_tai_offset - Sets the TAI offset from UTC and monotonic
@@ -2248,6 +2307,66 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
 }
 
 /**
+ * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex
+ */
+static int ntp_validate_timex(struct timex *txc)
+{
+       if (txc->modes & ADJ_ADJTIME) {
+               /* singleshot must not be used with any other mode bits */
+               if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
+                       return -EINVAL;
+               if (!(txc->modes & ADJ_OFFSET_READONLY) &&
+                   !capable(CAP_SYS_TIME))
+                       return -EPERM;
+       } else {
+               /* In order to modify anything, you gotta be super-user! */
+               if (txc->modes && !capable(CAP_SYS_TIME))
+                       return -EPERM;
+               /*
+                * if the quartz is off by more than 10% then
+                * something is VERY wrong!
+                */
+               if (txc->modes & ADJ_TICK &&
+                   (txc->tick <  900000/USER_HZ ||
+                    txc->tick > 1100000/USER_HZ))
+                       return -EINVAL;
+       }
+
+       if (txc->modes & ADJ_SETOFFSET) {
+               /* In order to inject time, you gotta be super-user! */
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               if (txc->modes & ADJ_NANO) {
+                       struct timespec ts;
+
+                       ts.tv_sec = txc->time.tv_sec;
+                       ts.tv_nsec = txc->time.tv_usec;
+                       if (!timespec_inject_offset_valid(&ts))
+                               return -EINVAL;
+
+               } else {
+                       if (!timeval_inject_offset_valid(&txc->time))
+                               return -EINVAL;
+               }
+       }
+
+       /*
+        * Check for potential multiplication overflows that can
+        * only happen on 64-bit systems:
+        */
+       if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) {
+               if (LLONG_MIN / PPM_SCALE > txc->freq)
+                       return -EINVAL;
+               if (LLONG_MAX / PPM_SCALE < txc->freq)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+/**
  * do_adjtimex() - Accessor function to NTP __do_adjtimex function
  */
 int do_adjtimex(struct timex *txc)
index d091467..44aec78 100644 (file)
@@ -10,7 +10,7 @@ extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,
 
 extern int timekeeping_valid_for_hres(void);
 extern u64 timekeeping_max_deferment(void);
-extern int timekeeping_inject_offset(struct timespec *ts);
+extern void timekeeping_warp_clock(void);
 extern int timekeeping_suspend(void);
 extern void timekeeping_resume(void);