public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Arnd Bergmann <arnd@arndb.de>
To: y2038@lists.linaro.org
Cc: kbuild test robot <lkp@intel.com>,
	"David S. Miller" <davem@davemloft.net>,
	Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>,
	netdev@vger.kernel.org, James Morris <jmorris@namei.org>,
	linux-kernel@vger.kernel.org,
	John Stultz <john.stultz@linaro.org>,
	kbuild-all@01.org, Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>,
	Thomas Gleixner <tglx@linutronix.de>,
	Patrick McHardy <kaber@trash.net>
Subject: [RFC v2] ipv4: avoid timespec in timestamp computation
Date: Wed, 30 Sep 2015 14:58:47 +0200	[thread overview]
Message-ID: <1751543.NxVe4t9vLP@wuerfel> (raw)
In-Reply-To: <1730636.Jx4pBXKUvN@wuerfel>

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 <arnd@arndb.de>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
v2: fixed build error reported by lkp@intel.com

diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index ec89d846324c..db8fc5171294 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -38,6 +38,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 274ed5e88456..44ecd7058946 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_since_midnight(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;
 				}

  reply	other threads:[~2015-09-30 12:58 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-30 11:26 [PATCH 00/12] net: assorted y2038 changes Arnd Bergmann
2015-09-30 11:26 ` [PATCH 01/12] net: fec: avoid timespec use Arnd Bergmann
2015-10-01 19:08   ` Richard Cochran
2015-09-30 11:26 ` [PATCH 02/12] net: stmmac: avoid using timespec Arnd Bergmann
2015-10-01 19:08   ` Richard Cochran
2015-09-30 11:26 ` [PATCH 03/12] net: igb: " Arnd Bergmann
2015-10-01 19:17   ` Richard Cochran
2015-10-01 20:01     ` Arnd Bergmann
2015-10-02  7:47       ` Richard Cochran
2015-09-30 11:26 ` [PATCH 04/12] mwifiex: use ktime_get_real for timestamping Arnd Bergmann
2015-10-09 11:36   ` Amitkumar Karwar
2015-09-30 11:26 ` [PATCH 05/12] mwifiex: avoid gettimeofday in ba_threshold setting Arnd Bergmann
2015-10-09 11:35   ` Amitkumar Karwar
2015-09-30 11:26 ` [PATCH 06/12] mac80211: use ktime_get_seconds Arnd Bergmann
2015-09-30 11:26 ` [PATCH 07/12] atm: hide 'struct zatm_t_hist' Arnd Bergmann
2015-09-30 15:24   ` Charles (Chas) Williams
2015-09-30 15:31     ` Arnd Bergmann
2015-09-30 15:32     ` [PATCH v2] atm: remove " Arnd Bergmann
2015-09-30 11:26 ` [PATCH 08/12] nfnetlink: use y2038 safe timestamp Arnd Bergmann
2015-10-02 12:53   ` Pablo Neira Ayuso
2015-10-02 21:23     ` Arnd Bergmann
2015-09-30 11:26 ` [PATCH 09/12] ipv6: use ktime_t for internal timestamps Arnd Bergmann
2015-09-30 11:26 ` [PATCH 10/12] net: sctp: avoid incorrect time_t use Arnd Bergmann
2015-09-30 13:57   ` Neil Horman
2015-09-30 14:15     ` Marcelo Ricardo Leitner
2015-09-30 14:19       ` Neil Horman
2015-09-30 14:28   ` Marcelo Ricardo Leitner
2015-09-30 11:26 ` [PATCH 11/12] [RFC] ipv4: avoid timespec in timestamp computation Arnd Bergmann
2015-09-30 11:55   ` kbuild test robot
2015-09-30 12:39     ` [Y2038] " Arnd Bergmann
2015-09-30 12:58       ` Arnd Bergmann [this message]
2015-09-30 12:15   ` [RFC PATCH] ipv4: ktime_get_ms_of_day() can be static kbuild test robot
2015-09-30 12:15   ` [PATCH 11/12] [RFC] ipv4: avoid timespec in timestamp computation kbuild test robot
2015-09-30 11:26 ` [PATCH 12/12] [RFC] can: avoid using timeval for uapi Arnd Bergmann
     [not found]   ` <1443612402-3000775-13-git-send-email-arnd-r2nGTMty4D4@public.gmane.org>
2015-10-05 18:51     ` Oliver Hartkopp
2015-10-06  8:32       ` Arnd Bergmann
2015-10-06  9:05         ` Marc Kleine-Budde
2015-10-06  9:18           ` Arnd Bergmann
2015-10-06  9:37             ` Marc Kleine-Budde
     [not found] ` <1443612402-3000775-1-git-send-email-arnd-r2nGTMty4D4@public.gmane.org>
2015-10-05 10:17   ` [PATCH 00/12] net: assorted y2038 changes David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1751543.NxVe4t9vLP@wuerfel \
    --to=arnd@arndb.de \
    --cc=davem@davemloft.net \
    --cc=jmorris@namei.org \
    --cc=john.stultz@linaro.org \
    --cc=kaber@trash.net \
    --cc=kbuild-all@01.org \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkp@intel.com \
    --cc=netdev@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=y2038@lists.linaro.org \
    --cc=yoshfuji@linux-ipv6.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox