diff mbox

[OPW,kernel] timekeeping: Added a function to return tv_sec portion of ktime_get_real_ts64()

Message ID 20141025145833.GA25231@heena.com
State New, archived
Headers show

Commit Message

Heena Sirwani Oct. 25, 2014, 2:58 p.m. UTC
The following patch adds a function to return tv_sec portion of
ktime_get_real_ts64() function in order to have a function that returns
seconds as 64-bit integers instead of 32-bit integers to address the
y2038 problem.

The function is similar to get_seconds() function except that it
includes read_seqcount_retry loop which is required for 32-bit
architectures. This is because 32-bit machines cannot access 64-bit
tk->xtime_sec variable atomically, requiring two 32-bit register loads
with the variable getting updated in the middle.

Signed-off-by: Heena Sirwani <heenasirwani@gmail.com>
---
 include/linux/timekeeping.h |    1 +
 kernel/time/timekeeping.c   |   23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

Comments

Arnd Bergmann Oct. 25, 2014, 3:08 p.m. UTC | #1
On Saturday 25 October 2014 20:28:33 Heena Sirwani wrote:
> The following patch adds a function to return tv_sec portion of
> ktime_get_real_ts64() function in order to have a function that returns
> seconds as 64-bit integers instead of 32-bit integers to address the
> y2038 problem.
> 
> The function is similar to get_seconds() function except that it
> includes read_seqcount_retry loop which is required for 32-bit
> architectures. This is because 32-bit machines cannot access 64-bit
> tk->xtime_sec variable atomically, requiring two 32-bit register loads
> with the variable getting updated in the middle.
> 
> Signed-off-by: Heena Sirwani <heenasirwani@gmail.com>

This code looks correct, and you have an excellent patch description
above. There is one small change I'd like you to make:

> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 93fc596..287bf23 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -673,6 +673,29 @@ time64_t ktime_get_seconds(void)
>  }
>  EXPORT_SYMBOL_GPL(ktime_get_seconds);
>  
> +time64_t ktime_get_real_seconds(void)
> +{
> +	struct timekeeper *tk = &tk_core.timekeeper;
> +	time64_t seconds;
> +	s32 nsec;
> +	unsigned int seq;
> +
> +	if (IS_ENABLED(CONFIG_64BIT))
> +		return tk->xtime_sec;
> +
> +	do {
> +		seq = read_seqcount_begin(&tk_core.seq);
> +		seconds = tk->xtime_sec;
> +		nsec = (long)(tk->tkr.xtime_nsec >> tk->tkr.shift);
> +
> +	} while (read_seqcount_retry(&tk_core.seq, seq));
> +
> +	if (nsec >= NSEC_PER_SEC)
> +		seconds += 1;
> +	return seconds;
> +}
> +EXPORT_SYMBOL(ktime_get_real_seconds);

The way that tk->tkr.xtime_nsec is used, we know that it can never
be greater than NSEC_PER_SEC if you are not adding anything on top,
so you can remove the local variable and the computation of the extra
second.

The lock is only required because on 32-bit architectures we cannot
access the tk->xtime_sec variable atomically as we can do on 64-bit.

	Arnd
diff mbox

Patch

diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 115d55e..91454de 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -29,6 +29,7 @@  struct timespec get_monotonic_coarse(void);
 extern void getrawmonotonic(struct timespec *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);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 93fc596..287bf23 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -673,6 +673,29 @@  time64_t ktime_get_seconds(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_seconds);
 
+time64_t ktime_get_real_seconds(void)
+{
+	struct timekeeper *tk = &tk_core.timekeeper;
+	time64_t seconds;
+	s32 nsec;
+	unsigned int seq;
+
+	if (IS_ENABLED(CONFIG_64BIT))
+		return tk->xtime_sec;
+
+	do {
+		seq = read_seqcount_begin(&tk_core.seq);
+		seconds = tk->xtime_sec;
+		nsec = (long)(tk->tkr.xtime_nsec >> tk->tkr.shift);
+
+	} while (read_seqcount_retry(&tk_core.seq, seq));
+
+	if (nsec >= NSEC_PER_SEC)
+		seconds += 1;
+	return seconds;
+}
+EXPORT_SYMBOL(ktime_get_real_seconds);
+
 #ifdef CONFIG_NTP_PPS
 
 /**