From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933564AbbI3L1u (ORCPT ); Wed, 30 Sep 2015 07:27:50 -0400 Received: from mout.kundenserver.de ([212.227.126.130]:58927 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933224AbbI3L1o (ORCPT ); Wed, 30 Sep 2015 07:27:44 -0400 From: Arnd Bergmann To: netdev@vger.kernel.org Cc: y2038@lists.linaro.org, linux-kernel@vger.kernel.org, "David S. Miller" , Arnd Bergmann , Alexey Kuznetsov , James Morris , Hideaki YOSHIFUJI , Patrick McHardy , John Stultz , Thomas Gleixner Subject: [PATCH 11/12] [RFC] ipv4: avoid timespec in timestamp computation Date: Wed, 30 Sep 2015 13:26:41 +0200 Message-Id: <1443612402-3000775-12-git-send-email-arnd@arndb.de> X-Mailer: git-send-email 2.1.0.rc2 In-Reply-To: <1443612402-3000775-1-git-send-email-arnd@arndb.de> References: <1443612402-3000775-1-git-send-email-arnd@arndb.de> X-Provags-ID: V03:K0:RgyCpi98GKxUeaSfmHakk8zEpgJq8CnREiZzPQEFLaoPtfxiYk8 2dcIf01wwqieyi7rzR7dL7ieQYs2uCeMbq5y3CeVBZsJR0R1WBZloLS8yDkMiIe1RWrKG1E h1BGFxDjUiBxUnnwNkospODyJ//nVqojAJ4aNRomMp/S76tNUvkFoAVn2lUc4UYgx4+wojy RpvlAWHWgm/4/5ictlvhA== X-UI-Out-Filterresults: notjunk:1;V01:K0:sPTPs+CtR/Q=:OEQjb4RUnnWW+Ad8a/iXFz W+NQqWZdfrOC8QnMh5uWfDtIAZlQCngAs3zZUpEvou+5agJEsYpSgatAR6QlLu4tJ04cD92kZ 6a4cdu5xPxZ4mvV2cWHnznu/kaUgfxIU+eOGkmjK/g89FNjAr+vcS7gtRrAsVOAcrWw2yZUuM tax+fScvoNbapJg15xT4EhKn3l5DlLfFHEJpYt3ClwG2HDPGW9Jm3n3xPLvWTK3MAjBZtPm4p 8i0ELuZoXqZvS/N0DNuMfEyw8qc7fjRHwOUoeWrqiQFv6NeZM9YAW2keG2nlpbR+1OO/6icwB IK/HVZhg3RBl9/Dhm7/IPQcJaDEdQCK+vP1kr1fDhiHx2RU1g0Kd7aXhDWNR9knkkX6CrcQq1 xUiDGFdZFguH1REg5KK2se/E59J9GOKC6tDFEgNCZK+dLCVRPF6SAdk/bmwZSLTjAv3YMia4K jQoKfv/tv9rbEcpxHV4bjkDddS32MaKwOZScNxcnO/H5fuoCqxyX1mcw4uSF7+s1dPv43ycTr tob7AsBTJI7hn7QCf+LXLUzmnbKIACFOfLr+RcFD1HMmVK1SllawVUYXnWQeERn5gDJvjPyqX EEkAE/lxrg+vEu2jwsNSaqpoD5sIuir8+ethk/IpSYorecCnF+HcsksS3RGEI6uBqVA+Tx03i ZPHrgUM7t5VGM6EAhJIb+YskXBKYud7Nt2iXqO1DH3nwpfEg25DQIiwWSdMWjxq1srU0= Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is an attempt to avoid the use of timespec in ipv4, where getnstimeofday() used to be used for computing the number of milliseconds since midnight, in three places. That computation would overflow in 2038 on 32-bit machines, and the normal workaround for this is to use timespec64, which in turn requires an expensive div_s64_mod() function call for calculating the seconds modulo 86400. Instead, this approach introduces a new generic helper function that does this more efficiently, by using only a 32-bit modulo (which the compiler can turn into two multiplications), relying on 39 bits to be sufficient for the current time of day. This is roughly 100 times faster than a full divmod operation on ARM. As a further optimization, this does not use the exact nanosecond value but instead relies tk_xtime() to report the time of the last jiffy, which is slightly less accurate, depending on the value of HZ. Signed-off-by: Arnd Bergmann Cc: Alexey Kuznetsov Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Cc: John Stultz Cc: Thomas Gleixner --- include/linux/timekeeping.h | 2 ++ kernel/time/timekeeping.c | 34 ++++++++++++++++++++++++++++++++++ net/ipv4/icmp.c | 8 +++----- net/ipv4/ip_options.c | 9 ++------- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index ca2eaa9077eb..3e126f8c2876 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -44,6 +44,8 @@ extern void ktime_get_ts64(struct timespec64 *ts); extern time64_t ktime_get_seconds(void); extern time64_t ktime_get_real_seconds(void); +extern u32 ktime_get_ms_since_midnight(void); + extern int __getnstimeofday64(struct timespec64 *tv); extern void getnstimeofday64(struct timespec64 *tv); extern void getboottime64(struct timespec64 *ts); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index ed5049ff94c5..3a1e030fa969 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -846,6 +846,40 @@ time64_t ktime_get_real_seconds(void) } EXPORT_SYMBOL_GPL(ktime_get_real_seconds); +#if IS_ENABLED(CONFIG_INET) +u32 ktime_get_ms_of_day(void) +{ + struct timekeeper *tk = &tk_core.timekeeper; + struct timespec64 now; + unsigned long seq; + u32 ms; + + /* we assume that the coarse time is good enough here */ + do { + seq = read_seqcount_begin(&tk_core.seq); + + now = tk_xtime(tk); + } while (read_seqcount_retry(&tk_core.seq, seq)); + + /* + * efficiently calculate the milliseconds since midnight: + * 86400 seconds per day == 2^7 * 675, which helps us + * replace an expensive div_s64_rem() with a hand-written + * 39-bit modulo on 32-bit architectures. + */ + if (!IS_ENABLED(CONFIG_64BIT)) + ms = (now.tv_sec & 0x7f) * MSEC_PER_SEC + + ((u32)(now.tv_sec >> 7) % 675) * 0x80 * MSEC_PER_SEC; + else + ms = (now.tv_sec % 86400) * MSEC_PER_SEC; + + ms += now.tv_nsec / NSEC_PER_MSEC; + + return ms; +} +EXPORT_SYMBOL_GPL(ktime_get_ms_since_midnight); +#endif + #ifdef CONFIG_NTP_PPS /** diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index e5eb8ac4089d..b1c53f2f7bd5 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -914,7 +914,6 @@ static bool icmp_echo(struct sk_buff *skb) */ static bool icmp_timestamp(struct sk_buff *skb) { - struct timespec tv; struct icmp_bxm icmp_param; /* * Too short. @@ -923,11 +922,10 @@ static bool icmp_timestamp(struct sk_buff *skb) goto out_err; /* - * Fill in the current time as ms since midnight UT: + * Fill in the current time as ms since midnight UT, + * this could probably be done faster. */ - getnstimeofday(&tv); - icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + - tv.tv_nsec / NSEC_PER_MSEC); + icmp_param.data.times[1] = htonl(ktime_get_ms_since_midnight()); icmp_param.data.times[2] = icmp_param.data.times[1]; if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) BUG(); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index bd246792360b..339ce528ecae 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -58,10 +58,8 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt, if (opt->ts_needaddr) ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); if (opt->ts_needtime) { - struct timespec tv; __be32 midtime; - getnstimeofday(&tv); - midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC); + midtime = htonl(ktime_get_ms_since_midnight()); memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); } return; @@ -415,10 +413,7 @@ int ip_options_compile(struct net *net, break; } if (timeptr) { - struct timespec tv; - u32 midtime; - getnstimeofday(&tv); - midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC; + u32 midtime = ktime_get_ms_since_midnight(); put_unaligned_be32(midtime, timeptr); opt->is_changed = 1; } -- 2.1.0.rc2