From patchwork Thu Oct 19 11:14:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 116361 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp365789qgn; Thu, 19 Oct 2017 04:15:19 -0700 (PDT) X-Google-Smtp-Source: ABhQp+Q4cuJ0ecubrOGaEo3TyGX1PqPBWVE5BstZFH9Yk+xvsziPS5ZolEDg3c8tmgOASQK3CW06 X-Received: by 10.101.78.5 with SMTP id r5mr1062363pgt.94.1508411719539; Thu, 19 Oct 2017 04:15:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1508411719; cv=none; d=google.com; s=arc-20160816; b=kGmQy6mLe800n/HzLnuNzsQ8V8X63AappwTqtJV6x38lBKW3gtK4+5/msGpPpXMvV1 G7zO45JOElb0GH7gvmHkNDjBCw/MxpKIv1jc2RhNBIPunB8NflFJVnl9JhcyOxjkU0Y+ ge6v9Uwo8Ng5g/yRNl7m9xnvJWiDOBuVV3cNnCTr6vQ0EQz5jDFjaaKnZhHPxal9QIwI 5Ss6WfYyOiyqoOvbSxwdT8GeDILfhoo3yiHFG7hTPHHYgujSPj9hmwiUXX6qe7HoUxmA +vyzg22czWSv9Sn48GvC19R1KmNPXhfkI18QnkuZMuqx0QebC07Wjw03bJ2A87skOToI sZog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=EgGjStpDYmTsPcXLLW7BGUq6AsaPfyJCtSYJ/JwCQLo=; b=O4BbxEYsQjTEmy4IJ2gRWBtt7P5R8yJI6PMw7z8fzAd+I5E3K7CgaAw5LD0LRMt6h9 HYps/uJQTGCTODMXuh187a1h0zhbxB0ECpxUkEM8795QoKeaaz47d8fE1uT3qMDc/YKH l8DHwbprAMOxFKvnvuHM6wcqXu6mbtP7z72GloLMs7cCkOyXf/33Vvg58s9DLzuVUsSe Lgm3h+Z+CxOVHko7ShfUJLeQGqvR+u/I8r9icnJIJh94wglyQW0BaLVSk6yyJkXBJLFa ZecYSK1mckbpKhLNPWhwbCWlmkk8iFqbAcBrXArt4BGN5Kg7RM82QndsT/wErG+HE7aA /AdQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m3si2657345pgs.564.2017.10.19.04.15.19; Thu, 19 Oct 2017 04:15:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752757AbdJSLPR (ORCPT + 27 others); Thu, 19 Oct 2017 07:15:17 -0400 Received: from mout.kundenserver.de ([217.72.192.73]:51451 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752108AbdJSLPP (ORCPT ); Thu, 19 Oct 2017 07:15:15 -0400 Received: from wuerfel.lan ([46.223.139.202]) by mrelayeu.kundenserver.de (mreue105 [212.227.15.145]) with ESMTPA (Nemesis) id 0MC1E8-1dwNLc06Ou-008psj; Thu, 19 Oct 2017 13:15:04 +0200 From: Arnd Bergmann To: Thomas Gleixner , y2038@lists.linaro.org Cc: Deepa Dinamani , John Stultz , Stephen Boyd , linux-kernel@vger.kernel.org, Arnd Bergmann Subject: [PATCH 1/7] timekeeping: consolidate timekeeping_inject_offset code Date: Thu, 19 Oct 2017 13:14:44 +0200 Message-Id: <20171019111450.3702205-1-arnd@arndb.de> X-Mailer: git-send-email 2.9.0 X-Provags-ID: V03:K0:ZWp54L5OWkFsKmFEa6LEtMmlMv9IxxbcCTPof5WffK82M+3Vrg2 6cbAVJ/BamxeJWKZqgBbkYE0bBtgT0KrRB9J4Gtom/P4i4MFRtPCD2JvTm/oFQINZGcH/IV YTvTJ6J7/xo4LfUzFgCscpoQ413jG1Dnsa59O/3J/VWHlhWxjlUoJL97A70dmM3XMMA4xnD Jt1cKQ36XIBRICwSse4LA== X-UI-Out-Filterresults: notjunk:1; V01:K0:cfsc9rt9364=:X0WAJ0eBID0x4BKiynatmj pGASX+8dyLWAcwLk1JEK0RyfcJzme4RvIKZIR5fSJ/JhEhZIF4enLB47CMjScZlcsGTQi0ygM LxE/W6TShUjOH3b8i6hG+CjlR0BM+F7HjmgfRmW63c7r5+qgTGXgr52Qb6PUaWwYoulaeqiSF DA0q3uaezUFiA7+tOBUMfcRqICje9B32jQOH35g6ztRDcb+kWZyc3+YOL/vvJxc7eYPJSDp6P J6PmLDSa3pvq3HXKeDsJ4zdBNrOMbfOxbt+bChPrL0Po00DppHwI5mT+z7tQ3iT6Vq+6MTbI5 NVgUfl0/DG5eLCSNAakxVke/68PR2tyzxkV7Huw9jfspg6ifWU67OAgNGAO+zmdKgop4UVoyB bdOWLXabueJNm9tWjy/I49H4zCLgemHv1GH8w2O+pkZESM/xlBVikz0KXYSITPogalPQutC9H TzDJPhNrgbpFmmpIys8ZC4RkOfBcUBbQme1JKVfMiTTuuqXUhlXuYXIjiUTsUPnEbX0Igy4nB XzsnsAPajUYcKYpL2WAgGD8b/5HipI5YR7ET35is+r72rnddef+iPvhCqGxMA6FHksj8oYHKn TLkPFJrcg6KTHKXoYSzsBWodNspcESVLSy2vRha6pw0LCFfH19U7i+iEzp7mkORus7neQICUy sgF7WD3/bR1oHQ/yzbun0FPdjt5zwXctO0+cvKBPQypH15c5xnbkQp65yDOUN2imM3fvMPDiO EtJnrt018NHfYYrNEqxbcEJjMuq7rkLRjnWxSQ== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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(). Signed-off-by: Arnd Bergmann --- include/linux/time.h | 26 ---------- kernel/time/ntp.c | 61 ---------------------- kernel/time/ntp_internal.h | 1 - kernel/time/time.c | 36 +------------ kernel/time/timekeeping.c | 123 ++++++++++++++++++++++++++++++++++++++++++++- kernel/time/timekeeping.h | 2 +- 6 files changed, 123 insertions(+), 126 deletions(-) -- 2.9.0 diff --git a/include/linux/time.h b/include/linux/time.h index 9bc1f945777c..c0fbad08448f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -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 diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index edf19cc53140..a5e702669d84 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -653,67 +653,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. diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index d8a7c11fa71a..74b52cd48209 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h @@ -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 */ diff --git a/kernel/time/time.c b/kernel/time/time.c index 44a8c1402133..04684e294f00 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -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) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 8af77006e937..679dbfbea419 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1300,13 +1300,39 @@ int do_settimeofday64(const struct timespec64 *ts) } 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; @@ -1345,7 +1371,40 @@ int timekeeping_inject_offset(struct timespec *ts) 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 @@ -2290,6 +2349,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) diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h index d0914676d4c5..44aec7893cdd 100644 --- a/kernel/time/timekeeping.h +++ b/kernel/time/timekeeping.h @@ -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);