This patch introduces some functions for converting cputime to timespec64 and back, that repalce the timespec type with timespec64 type, as well as for arch/s390 and arch/powerpc architecture.
And these new methods will replace the old cputime_to_timespec/timespec_to_cputime function to ready for 2038 issue.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- arch/powerpc/include/asm/cputime.h | 24 ++++++++++++++++++++++++ arch/s390/include/asm/cputime.h | 26 ++++++++++++++++++++++++++ include/asm-generic/cputime_jiffies.h | 8 ++++++++ include/linux/jiffies.h | 3 +++ kernel/time/time.c | 21 +++++++++++++++++++++ 5 files changed, 82 insertions(+)
diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index e245255..5a2b5ce 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h @@ -178,6 +178,30 @@ static inline cputime_t timespec_to_cputime(const struct timespec *p) }
/* + * Convert cputime <-> timespec64 + */ +static inline void cputime_to_timespec64(const cputime_t ct, struct timespec64 *p) +{ + u64 x = (__force u64) ct; + unsigned int frac; + + frac = do_div(x, tb_ticks_per_sec); + p->tv_sec = x; + x = (u64) frac * 1000000000; + do_div(x, tb_ticks_per_sec); + p->tv_nsec = x; +} + +static inline cputime_t timespec64_to_cputime(const struct timespec64 *p) +{ + u64 ct; + + ct = (u64) p->tv_nsec * tb_ticks_per_sec; + do_div(ct, 1000000000); + return (__force cputime_t)(ct + (u64) p->tv_sec * tb_ticks_per_sec); +} + +/* * Convert cputime <-> timeval */ static inline void cputime_to_timeval(const cputime_t ct, struct timeval *p) diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index b91e960..caec0a0 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -115,6 +115,32 @@ static inline void cputime_to_timespec(const cputime_t cputime, }
/* + * Convert cputime to timespec64 and back. + */ +static inline cputime_t timespec64_to_cputime(const struct timespec64 *value) +{ + unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC; + return (__force cputime_t)(ret + __div(value->tv_nsec * CPUTIME_PER_USEC, NSEC_PER_USEC)); +} + +static inline void cputime_to_timespec64(const cputime_t cputime, + struct timespec64 *value) +{ + unsigned long long __cputime = (__force unsigned long long) cputime; +#ifndef CONFIG_64BIT + register_pair rp; + + rp.pair = __cputime >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_SEC / 2)); + value->tv_nsec = rp.subreg.even * NSEC_PER_USEC / CPUTIME_PER_USEC; + value->tv_sec = rp.subreg.odd; +#else + value->tv_nsec = (__cputime % CPUTIME_PER_SEC) * NSEC_PER_USEC / CPUTIME_PER_USEC; + value->tv_sec = __cputime / CPUTIME_PER_SEC; +#endif +} + +/* * Convert cputime to timeval and back. * Since cputime and timeval have the same resolution (microseconds) * this is easy. diff --git a/include/asm-generic/cputime_jiffies.h b/include/asm-generic/cputime_jiffies.h index fe386fc..e9c28e1 100644 --- a/include/asm-generic/cputime_jiffies.h +++ b/include/asm-generic/cputime_jiffies.h @@ -52,6 +52,14 @@ typedef u64 __nocast cputime64_t; jiffies_to_timespec(cputime_to_jiffies(__ct),__val)
/* + * Convert cputime to timespec64 and abck. + */ +#define timespec64_to_cputime(__val) \ + jiffies_to_cputime(timespec64_to_jiffies(__val)) +#define cputime_to_timespec64(__ct,__val) \ + jiffies_to_timespec64(cputime_to_jiffies(__ct),__val) + +/* * Convert cputime to timeval and back. */ #define timeval_to_cputime(__val) \ diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c367cbd..dbaa4ee 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -293,6 +293,9 @@ extern unsigned long usecs_to_jiffies(const unsigned int u); extern unsigned long timespec_to_jiffies(const struct timespec *value); extern void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value); +extern unsigned long timespec64_to_jiffies(const struct timespec64 *value); +extern void jiffies_to_timespec64(const unsigned long jiffies, + struct timespec64 *value); extern unsigned long timeval_to_jiffies(const struct timeval *value); extern void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value); diff --git a/kernel/time/time.c b/kernel/time/time.c index 2c85b77..d5978c5 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -606,6 +606,27 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) } EXPORT_SYMBOL(jiffies_to_timespec);
+unsigned long +timespec64_to_jiffies(const struct timespec64 *value) +{ + return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); +} +EXPORT_SYMBOL(timespec64_to_jiffies); + +void +jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value) +{ + /* + * Convert jiffies to nanoseconds and separate with + * one divide. + */ + u32 rem; + value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC, + NSEC_PER_SEC, &rem); + value->tv_nsec = rem; +} +EXPORT_SYMBOL(jiffies_to_timespec64); + /* * We could use a similar algorithm to timespec_to_jiffies (with a * different multiplier for usec instead of nsec). But this has a