This patch series change the 32-bit time type (timespec/itimerspec) to the 64-bit one (timespec64/itimerspec64), since 32-bit time types will break in the year 2038.
This patch series introduce new methods with timespec64/itimerspec64 type, and remove the old ones with timespec/itimerspec type for posix_clock_operations and k_clock structure.
Changes since v4: - Modify the conversion between the itimerspec64 and itimerspec for 64bit. - Continue to split up and merge the patch. - Explain more for the patch log. - Re-order the patch of the patch series.
Next step will replace the other callback pointers of k_clock structure.
Baolin Wang (11): linux/time64.h:Introduce the 'struct itimerspec64' for 64bit timekeeping:Introduce the current_kernel_time64() function with timespec64 type time/hrtimer:Introduce hrtimer_get_res64() with timespec64 type for getting the timer resolution posix timers:Introduce the 64bit methods with timespec64 type for k_clock structure time/posix-timers:Convert to the 64bit methods for k_clock callback functions char/mmtimer:Convert to the 64bit methods for k_clock callback function time/alarmtimer:Convert to the new methods for k_clock structure time/posix-clock:Convert to the 64bit methods for k_clock and posix_clock_operations structure cputime:Introduce the cputime_to_timespec64/timespec64_to_cputime function time/posix-cpu-timers:Convert to the 64bit methods for k_clock structure k_clock:Remove the 32bit methods with timespec type
arch/powerpc/include/asm/cputime.h | 24 +++++ arch/s390/include/asm/cputime.h | 26 ++++++ drivers/char/mmtimer.c | 36 ++++---- drivers/ptp/ptp_clock.c | 26 ++---- include/asm-generic/cputime_jiffies.h | 8 ++ include/linux/hrtimer.h | 12 ++- include/linux/jiffies.h | 3 + include/linux/posix-clock.h | 10 +-- include/linux/posix-timers.h | 18 ++-- include/linux/time64.h | 45 ++++++++++ include/linux/timekeeping.h | 14 ++- kernel/time/alarmtimer.c | 43 ++++----- kernel/time/hrtimer.c | 10 +-- kernel/time/posix-clock.c | 20 ++--- kernel/time/posix-cpu-timers.c | 83 +++++++++-------- kernel/time/posix-timers.c | 157 +++++++++++++++++++-------------- kernel/time/time.c | 21 +++++ kernel/time/timekeeping.c | 6 +- kernel/time/timekeeping.h | 2 +- 19 files changed, 365 insertions(+), 199 deletions(-)
This patch introduces the 'struct itimerspec64' for 64bit to replace itimerspec, and also introduces the conversion methods: itimerspec64_to_itimerspec() and itimerspec_to_itimerspec64().
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/time64.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/include/linux/time64.h b/include/linux/time64.h index a383147..0193a63 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -18,6 +18,11 @@ struct timespec64 { }; #endif
+struct itimerspec64 { + struct timespec64 it_interval; /* timer period */ + struct timespec64 it_value; /* timer expiration */ +}; + /* Parameters used to convert the timespec values: */ #define MSEC_PER_SEC 1000L #define USEC_PER_MSEC 1000L @@ -43,6 +48,24 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) return ts; }
+static inline struct itimerspec itimerspec64_to_itimerspec(const struct itimerspec64 its64) +{ + struct itimerspec ret; + + ret.it_interval = its64.it_interval; + ret.it_value = its64.it_value; + return ret; +} + +static inline struct itimerspec64 itimerspec_to_itimerspec64(const struct itimerspec its) +{ + struct itimerspec64 ret; + + ret.it_interval = its.it_interval; + ret.it_value = its.it_value; + return ret; +} + # define timespec64_equal timespec_equal # define timespec64_compare timespec_compare # define set_normalized_timespec64 set_normalized_timespec @@ -75,6 +98,28 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) return ret; }
+static inline struct itimerspec itimerspec64_to_itimerspec(const struct itimerspec64 its64) +{ + struct itimerspec ret; + + ret.it_interval.tv_sec = (time_t)its64.it_interval.tv_sec; + ret.it_interval.tv_nsec = its64.it_interval.tv_nsec; + ret.it_value.tv_sec = (time_t)its64.it_value.tv_sec; + ret.it_value.tv_nsec = its64.it_value.tv_nsec; + return ret; +} + +static inline struct itimerspec64 itimerspec_to_itimerspec64(const struct itimerspec its) +{ + struct itimerspec64 ret; + + ret.it_interval.tv_sec = its.it_interval.tv_sec; + ret.it_interval.tv_nsec = its.it_interval.tv_nsec; + ret.it_value.tv_sec = its.it_value.tv_sec; + ret.it_value.tv_nsec = its.it_value.tv_nsec; + return ret; +} + static inline int timespec64_equal(const struct timespec64 *a, const struct timespec64 *b) {
On Friday 17 April 2015 14:47:08 Baolin Wang wrote:
This patch introduces the 'struct itimerspec64' for 64bit to replace itimerspec, and also introduces the conversion methods: itimerspec64_to_itimerspec() and itimerspec_to_itimerspec64().
Signed-off-by: Baolin Wang baolin.wang@linaro.org
include/linux/time64.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/include/linux/time64.h b/include/linux/time64.h index a383147..0193a63 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -18,6 +18,11 @@ struct timespec64 { }; #endif +struct itimerspec64 {
- struct timespec64 it_interval; /* timer period */
- struct timespec64 it_value; /* timer expiration */
+};
Ok, you chose to have a definition for itimerspec64 that is the same for 32-bit and 64-bit machines. I think that's ok, but then you don't need to duplicate the other functions for the two cases:
/* Parameters used to convert the timespec values: */ #define MSEC_PER_SEC 1000L #define USEC_PER_MSEC 1000L @@ -43,6 +48,24 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) return ts; } +static inline struct itimerspec itimerspec64_to_itimerspec(const struct itimerspec64 its64) +{
- struct itimerspec ret;
- ret.it_interval = its64.it_interval;
- ret.it_value = its64.it_value;
- return ret;
+} +static inline struct itimerspec itimerspec64_to_itimerspec(const struct itimerspec64 its64) +{
- struct itimerspec ret;
- ret.it_interval.tv_sec = (time_t)its64.it_interval.tv_sec;
- ret.it_interval.tv_nsec = its64.it_interval.tv_nsec;
- ret.it_value.tv_sec = (time_t)its64.it_value.tv_sec;
- ret.it_value.tv_nsec = its64.it_value.tv_nsec;
- return ret;
+}
Both of these can be expressed using
ret.it_interval = timespec64_to_timespec(its64.it_interval); ret.it_value = timespec64_to_timespec(its64.it_value);
outside of the #ifdef.
The alternative would be to do as I suggested and use "#define itimerspec64_to_itimerspec(its) (its)" in your first version, but add a matching #define for the type, like we have for time_t.
Arnd
This patch adds current_kernel_time64() function with timespec64 type, and makes current_kernel_time() 'static inline' and moves it to timekeeping.h file.
It is convenient for user to get the current kernel time with timespec64 type, and delete the current_kernel_time() function easily in timekeeping.h file. That is ready for 2038 when get the current time.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/timekeeping.h | 10 +++++++++- kernel/time/timekeeping.c | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 3eaae47..c6d5ae9 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -18,10 +18,18 @@ extern int do_sys_settimeofday(const struct timespec *tv, * Kernel time accessors */ unsigned long get_seconds(void); -struct timespec current_kernel_time(void); +struct timespec64 current_kernel_time64(void); /* does not take xtime_lock */ struct timespec __current_kernel_time(void);
+static inline struct timespec current_kernel_time(void) +{ + struct timespec64 now; + + now = current_kernel_time64(); + return timespec64_to_timespec(now); +} + /* * timespec based interfaces */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 91db941..8ccc02c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1721,7 +1721,7 @@ struct timespec __current_kernel_time(void) return timespec64_to_timespec(tk_xtime(tk)); }
-struct timespec current_kernel_time(void) +struct timespec64 current_kernel_time64(void) { struct timekeeper *tk = &tk_core.timekeeper; struct timespec64 now; @@ -1733,9 +1733,9 @@ struct timespec current_kernel_time(void) now = tk_xtime(tk); } while (read_seqcount_retry(&tk_core.seq, seq));
- return timespec64_to_timespec(now); + return now; } -EXPORT_SYMBOL(current_kernel_time); +EXPORT_SYMBOL(current_kernel_time64);
struct timespec64 get_monotonic_coarse64(void) {
This patch introduces hrtimer_get_res64() function to get the timer resolution with timespec64 type, and moves the hrtimer_get_res() function into include/linux/hrtimer.h as a 'static inline' helper that just calls hrtimer_get_res64.
It is ready for 2038 year when getting the timer resolution by hrtimer_get_res64() function with timespec64 type, and it is convenient to delete the old hrtimer_get_res() function in hrtimer.h file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/hrtimer.h | 12 +++++++++++- kernel/time/hrtimer.c | 10 +++++----- 2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 05f6df1..ee8ed44 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -383,7 +383,17 @@ static inline int hrtimer_restart(struct hrtimer *timer)
/* Query timers: */ extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); -extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); +extern int hrtimer_get_res64(const clockid_t which_clock, + struct timespec64 *tp); + +static inline int hrtimer_get_res(const clockid_t which_clock, + struct timespec *tp) +{ + struct timespec64 *ts64; + + *ts64 = timespec_to_timespec64(*tp); + return hrtimer_get_res64(which_clock, ts64); +}
extern ktime_t hrtimer_get_next_event(void);
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index bee0c1f..508d936 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1175,24 +1175,24 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, EXPORT_SYMBOL_GPL(hrtimer_init);
/** - * hrtimer_get_res - get the timer resolution for a clock + * hrtimer_get_res64 - get the timer resolution for a clock * @which_clock: which clock to query - * @tp: pointer to timespec variable to store the resolution + * @tp: pointer to timespec64 variable to store the resolution * * Store the resolution of the clock selected by @which_clock in the * variable pointed to by @tp. */ -int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) +int hrtimer_get_res64(const clockid_t which_clock, struct timespec64 *tp) { struct hrtimer_cpu_base *cpu_base; int base = hrtimer_clockid_to_base(which_clock);
cpu_base = raw_cpu_ptr(&hrtimer_bases); - *tp = ktime_to_timespec(cpu_base->clock_base[base].resolution); + *tp = ktime_to_timespec64(cpu_base->clock_base[base].resolution);
return 0; } -EXPORT_SYMBOL_GPL(hrtimer_get_res); +EXPORT_SYMBOL_GPL(hrtimer_get_res64);
static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) {
This patch introduces the new methods with timespec64 type for k_clcok structure, converts the timepsec type to timespec64 type in k_clock structure and converts the itimerspec type to itimerspec64 type to ready for 2038 issue.
And also introduces the 64bit methods with timespec64 type for the framework functions.
Next step will migrate all the k_clock users to use the new methods with timespec64 type and itimerspec64 type, and it contains the files of posix-timers.c, mmtimer.c, alarmtimer.c, posix-clock.c and posix-cpu-timers.c.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 9 ++++++ kernel/time/posix-timers.c | 65 ++++++++++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 907f3fd..35786c5 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -98,9 +98,13 @@ struct k_itimer {
struct k_clock { int (*clock_getres) (const clockid_t which_clock, struct timespec *tp); + int (*clock_getres64) (const clockid_t which_clock, struct timespec64 *tp); int (*clock_set) (const clockid_t which_clock, const struct timespec *tp); + int (*clock_set64) (const clockid_t which_clock, + const struct timespec64 *tp); int (*clock_get) (const clockid_t which_clock, struct timespec * tp); + int (*clock_get64) (const clockid_t which_clock, struct timespec64 *tp); int (*clock_adj) (const clockid_t which_clock, struct timex *tx); int (*timer_create) (struct k_itimer *timer); int (*nsleep) (const clockid_t which_clock, int flags, @@ -109,10 +113,15 @@ struct k_clock { int (*timer_set) (struct k_itimer * timr, int flags, struct itimerspec * new_setting, struct itimerspec * old_setting); + int (*timer_set64) (struct k_itimer *timr, int flags, + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting); int (*timer_del) (struct k_itimer * timr); #define TIMER_RETRY 1 void (*timer_get) (struct k_itimer * timr, struct itimerspec * cur_setting); + void (*timer_get64) (struct k_itimer *timr, + struct itimerspec64 *cur_setting); };
extern struct k_clock clock_posix_cpu; diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 31ea01f..9070387 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -522,13 +522,13 @@ void posix_timers_register_clock(const clockid_t clock_id, return; }
- if (!new_clock->clock_get) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_get()\n", + if (!new_clock->clock_get && !new_clock->clock_get64) { + printk(KERN_WARNING "POSIX clock id %d lacks clock_get() and clock_get64()\n", clock_id); return; } - if (!new_clock->clock_getres) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_getres()\n", + if (!new_clock->clock_getres && !new_clock->clock_getres64) { + printk(KERN_WARNING "POSIX clock id %d lacks clock_getres() and clock_getres64()\n", clock_id); return; } @@ -579,7 +579,7 @@ static struct k_clock *clockid_to_kclock(const clockid_t id) return (id & CLOCKFD_MASK) == CLOCKFD ? &clock_posix_dynamic : &clock_posix_cpu;
- if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) + if (id >= MAX_CLOCKS || (!posix_clocks[id].clock_getres && !posix_clocks[id].clock_getres64)) return NULL; return &posix_clocks[id]; } @@ -771,6 +771,7 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, struct itimerspec __user *, setting) { struct itimerspec cur_setting; + struct itimerspec64 cur_setting64; struct k_itimer *timr; struct k_clock *kc; unsigned long flags; @@ -781,10 +782,16 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || !kc->timer_get)) + if (WARN_ON_ONCE(!kc || (!kc->timer_get && !kc->timer_get64))) { ret = -EINVAL; - else - kc->timer_get(timr, &cur_setting); + } else { + if (kc->timer_get64) { + kc->timer_get64(timr, &cur_setting64); + cur_setting = itimerspec64_to_itimerspec(cur_setting64); + } else { + kc->timer_get(timr, &cur_setting); + } + }
unlock_timer(timr, flags);
@@ -877,6 +884,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, { struct k_itimer *timr; struct itimerspec new_spec, old_spec; + struct itimerspec64 new_spec64, old_spec64; int error = 0; unsigned long flag; struct itimerspec *rtn = old_setting ? &old_spec : NULL; @@ -897,10 +905,19 @@ retry: return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || !kc->timer_set)) + if (WARN_ON_ONCE(!kc || (!kc->timer_set && !kc->timer_set64))) { error = -EINVAL; - else - error = kc->timer_set(timr, flags, &new_spec, rtn); + } else { + if (kc->timer_set64) { + new_spec64 = itimerspec_to_itimerspec64(new_spec); + error = kc->timer_set64(timr, flags, &new_spec64, + &old_spec64); + if (old_setting) + old_spec = itimerspec64_to_itimerspec(old_spec64); + } else { + error = kc->timer_set(timr, flags, &new_spec, rtn); + } + }
unlock_timer(timr, flag); if (error == TIMER_RETRY) { @@ -1007,14 +1024,20 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec new_tp; + struct timespec64 new_tp64;
- if (!kc || !kc->clock_set) + if (!kc || (!kc->clock_set && !kc->clock_set64)) return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
- return kc->clock_set(which_clock, &new_tp); + if (kc->clock_set64) { + new_tp64 = timespec_to_timespec64(new_tp); + return kc->clock_set64(which_clock, &new_tp64); + } else { + return kc->clock_set(which_clock, &new_tp); + } }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, @@ -1022,12 +1045,18 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec kernel_tp; + struct timespec64 kernel_tp64; int error;
if (!kc) return -EINVAL;
- error = kc->clock_get(which_clock, &kernel_tp); + if (kc->clock_get64) { + error = kc->clock_get64(which_clock, &kernel_tp64); + kernel_tp = timespec64_to_timespec(kernel_tp64); + } else { + error = kc->clock_get(which_clock, &kernel_tp); + }
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) error = -EFAULT; @@ -1063,12 +1092,18 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec rtn_tp; + struct timespec64 rtn_tp64; int error;
if (!kc) return -EINVAL;
- error = kc->clock_getres(which_clock, &rtn_tp); + if (kc->clock_getres64) { + error = kc->clock_getres64(which_clock, &rtn_tp64); + rtn_tp = timespec64_to_timespec(rtn_tp64); + } else { + error = kc->clock_getres(which_clock, &rtn_tp); + }
if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) error = -EFAULT;
This patch converts the timepsec type to timespec64 type, and converts the itimerspec type to itimerspec64 type for the k_clock callback functions.
This patch also converts the timespec type to timespec64 type for timekeeping_clocktai() function which is used only in the posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/timekeeping.h | 4 +- kernel/time/posix-timers.c | 102 +++++++++++++++++++++++-------------------- kernel/time/timekeeping.h | 2 +- 3 files changed, 57 insertions(+), 51 deletions(-)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index c6d5ae9..bd3df93 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -242,9 +242,9 @@ static inline void get_monotonic_boottime64(struct timespec64 *ts) *ts = ktime_to_timespec64(ktime_get_boottime()); }
-static inline void timekeeping_clocktai(struct timespec *ts) +static inline void timekeeping_clocktai(struct timespec64 *ts) { - *ts = ktime_to_timespec(ktime_get_clocktai()); + *ts = ktime_to_timespec64(ktime_get_clocktai()); }
/* diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 9070387..47d1abf 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -132,9 +132,9 @@ static struct k_clock posix_clocks[MAX_CLOCKS]; static int common_nsleep(const clockid_t, int flags, struct timespec *t, struct timespec __user *rmtp); static int common_timer_create(struct k_itimer *new_timer); -static void common_timer_get(struct k_itimer *, struct itimerspec *); +static void common_timer_get(struct k_itimer *, struct itimerspec64 *); static int common_timer_set(struct k_itimer *, int, - struct itimerspec *, struct itimerspec *); + struct itimerspec64 *, struct itimerspec64 *); static int common_timer_del(struct k_itimer *timer);
static enum hrtimer_restart posix_timer_fn(struct hrtimer *data); @@ -203,17 +203,20 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags) }
/* Get clock_realtime */ -static int posix_clock_realtime_get(clockid_t which_clock, struct timespec *tp) +static int posix_clock_realtime_get(clockid_t which_clock, + struct timespec64 *tp) { - ktime_get_real_ts(tp); + ktime_get_real_ts64(tp); return 0; }
/* Set clock_realtime */ static int posix_clock_realtime_set(const clockid_t which_clock, - const struct timespec *tp) + const struct timespec64 *tp) { - return do_sys_settimeofday(tp, NULL); + struct timespec ts = timespec64_to_timespec(*tp); + + return do_sys_settimeofday(&ts, NULL); }
static int posix_clock_realtime_adj(const clockid_t which_clock, @@ -225,48 +228,51 @@ static int posix_clock_realtime_adj(const clockid_t which_clock, /* * Get monotonic time for posix timers */ -static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp) +static int posix_ktime_get_ts(clockid_t which_clock, struct timespec64 *tp) { - ktime_get_ts(tp); + ktime_get_ts64(tp); return 0; }
/* * Get monotonic-raw time for posix timers */ -static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp) +static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec64 *tp) { - getrawmonotonic(tp); + getrawmonotonic64(tp); return 0; }
-static int posix_get_realtime_coarse(clockid_t which_clock, struct timespec *tp) +static int posix_get_realtime_coarse(clockid_t which_clock, + struct timespec64 *tp) { - *tp = current_kernel_time(); + *tp = current_kernel_time64(); return 0; }
static int posix_get_monotonic_coarse(clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { - *tp = get_monotonic_coarse(); + *tp = get_monotonic_coarse64(); return 0; }
-static int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp) +static int posix_get_coarse_res(const clockid_t which_clock, + struct timespec64 *tp) { - *tp = ktime_to_timespec(KTIME_LOW_RES); + *tp = ktime_to_timespec64(KTIME_LOW_RES); return 0; }
-static int posix_get_boottime(const clockid_t which_clock, struct timespec *tp) +static int posix_get_boottime(const clockid_t which_clock, + struct timespec64 *tp) { - get_monotonic_boottime(tp); + get_monotonic_boottime64(tp); return 0; }
-static int posix_get_tai(clockid_t which_clock, struct timespec *tp) +static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp) { timekeeping_clocktai(tp); return 0; @@ -278,57 +284,57 @@ static int posix_get_tai(clockid_t which_clock, struct timespec *tp) static __init int init_posix_timers(void) { struct k_clock clock_realtime = { - .clock_getres = hrtimer_get_res, - .clock_get = posix_clock_realtime_get, - .clock_set = posix_clock_realtime_set, + .clock_getres64 = hrtimer_get_res64, + .clock_get64 = posix_clock_realtime_get, + .clock_set64 = posix_clock_realtime_set, .clock_adj = posix_clock_realtime_adj, .nsleep = common_nsleep, .nsleep_restart = hrtimer_nanosleep_restart, .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, + .timer_set64 = common_timer_set, + .timer_get64 = common_timer_get, .timer_del = common_timer_del, }; struct k_clock clock_monotonic = { - .clock_getres = hrtimer_get_res, - .clock_get = posix_ktime_get_ts, + .clock_getres64 = hrtimer_get_res64, + .clock_get64 = posix_ktime_get_ts, .nsleep = common_nsleep, .nsleep_restart = hrtimer_nanosleep_restart, .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, + .timer_set64 = common_timer_set, + .timer_get64 = common_timer_get, .timer_del = common_timer_del, }; struct k_clock clock_monotonic_raw = { - .clock_getres = hrtimer_get_res, - .clock_get = posix_get_monotonic_raw, + .clock_getres64 = hrtimer_get_res64, + .clock_get64 = posix_get_monotonic_raw, }; struct k_clock clock_realtime_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_realtime_coarse, + .clock_getres64 = posix_get_coarse_res, + .clock_get64 = posix_get_realtime_coarse, }; struct k_clock clock_monotonic_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_monotonic_coarse, + .clock_getres64 = posix_get_coarse_res, + .clock_get64 = posix_get_monotonic_coarse, }; struct k_clock clock_tai = { - .clock_getres = hrtimer_get_res, - .clock_get = posix_get_tai, + .clock_getres64 = hrtimer_get_res64, + .clock_get64 = posix_get_tai, .nsleep = common_nsleep, .nsleep_restart = hrtimer_nanosleep_restart, .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, + .timer_set64 = common_timer_set, + .timer_get64 = common_timer_get, .timer_del = common_timer_del, }; struct k_clock clock_boottime = { - .clock_getres = hrtimer_get_res, - .clock_get = posix_get_boottime, + .clock_getres64 = hrtimer_get_res64, + .clock_get64 = posix_get_boottime, .nsleep = common_nsleep, .nsleep_restart = hrtimer_nanosleep_restart, .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, + .timer_set64 = common_timer_set, + .timer_get64 = common_timer_get, .timer_del = common_timer_del, };
@@ -726,7 +732,7 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags) * report. */ static void -common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) +common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) { ktime_t now, remaining, iv; struct hrtimer *timer = &timr->it.real.timer; @@ -737,7 +743,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
/* interval timer ? */ if (iv.tv64) - cur_setting->it_interval = ktime_to_timespec(iv); + cur_setting->it_interval = ktime_to_timespec64(iv); else if (!hrtimer_active(timer) && (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) return; @@ -763,7 +769,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) cur_setting->it_value.tv_nsec = 1; } else - cur_setting->it_value = ktime_to_timespec(remaining); + cur_setting->it_value = ktime_to_timespec64(remaining); }
/* Get the time remaining on a POSIX.1b interval timer. */ @@ -830,7 +836,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) /* timr->it_lock is taken. */ static int common_timer_set(struct k_itimer *timr, int flags, - struct itimerspec *new_setting, struct itimerspec *old_setting) + struct itimerspec64 *new_setting, struct itimerspec64 *old_setting) { struct hrtimer *timer = &timr->it.real.timer; enum hrtimer_mode mode; @@ -859,10 +865,10 @@ common_timer_set(struct k_itimer *timr, int flags, hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); timr->it.real.timer.function = posix_timer_fn;
- hrtimer_set_expires(timer, timespec_to_ktime(new_setting->it_value)); + hrtimer_set_expires(timer, timespec64_to_ktime(new_setting->it_value));
/* Convert interval */ - timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); + timr->it.real.interval = timespec64_to_ktime(new_setting->it_interval);
/* SIGEV_NONE timers are not queued ! See common_timer_get */ if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h index 1d91416..144af14 100644 --- a/kernel/time/timekeeping.h +++ b/kernel/time/timekeeping.h @@ -15,7 +15,7 @@ extern u64 timekeeping_max_deferment(void); extern int timekeeping_inject_offset(struct timespec *ts); extern s32 timekeeping_get_tai_offset(void); extern void timekeeping_set_tai_offset(s32 tai_offset); -extern void timekeeping_clocktai(struct timespec *ts); +extern void timekeeping_clocktai(struct timespec64 *ts); extern int timekeeping_suspend(void); extern void timekeeping_resume(void);
This patch converts to the 64bit methods for k_clock callback function, that converts the timespec type to timespec64 type and converts the itimerspec type to itimerspec64 type.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- drivers/char/mmtimer.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 3d6c067..213d0bb 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -478,18 +478,18 @@ static int sgi_clock_period; static struct timespec sgi_clock_offset; static int sgi_clock_period;
-static int sgi_clock_get(clockid_t clockid, struct timespec *tp) +static int sgi_clock_get(clockid_t clockid, struct timespec64 *tp) { u64 nsec;
nsec = rtc_time() * sgi_clock_period + sgi_clock_offset.tv_nsec; - *tp = ns_to_timespec(nsec); + *tp = ns_to_timespec64(nsec); tp->tv_sec += sgi_clock_offset.tv_sec; return 0; };
-static int sgi_clock_set(const clockid_t clockid, const struct timespec *tp) +static int sgi_clock_set(const clockid_t clockid, const struct timespec64 *tp) {
u64 nsec; @@ -657,7 +657,7 @@ static int sgi_timer_del(struct k_itimer *timr) }
/* Assumption: it_lock is already held with irq's disabled */ -static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) +static void sgi_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) {
if (timr->it.mmtimer.clock == TIMER_OFF) { @@ -668,14 +668,14 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) return; }
- cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period); - cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period); + cur_setting->it_interval = ns_to_timespec64(timr->it.mmtimer.incr * sgi_clock_period); + cur_setting->it_value = ns_to_timespec64((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period); }
static int sgi_timer_set(struct k_itimer *timr, int flags, - struct itimerspec * new_setting, - struct itimerspec * old_setting) + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting) { unsigned long when, period, irqflags; int err = 0; @@ -687,8 +687,8 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, sgi_timer_get(timr, old_setting);
sgi_timer_del(timr); - when = timespec_to_ns(&new_setting->it_value); - period = timespec_to_ns(&new_setting->it_interval); + when = timespec64_to_ns(&new_setting->it_value); + period = timespec64_to_ns(&new_setting->it_interval);
if (when == 0) /* Clear timer */ @@ -699,11 +699,9 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, return -ENOMEM;
if (flags & TIMER_ABSTIME) { - struct timespec n; unsigned long now;
- getnstimeofday(&n); - now = timespec_to_ns(&n); + now = ktime_get_real_ns(); if (when > now) when -= now; else @@ -765,7 +763,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, return err; }
-static int sgi_clock_getres(const clockid_t which_clock, struct timespec *tp) +static int sgi_clock_getres(const clockid_t which_clock, struct timespec64 *tp) { tp->tv_sec = 0; tp->tv_nsec = sgi_clock_period; @@ -773,13 +771,13 @@ static int sgi_clock_getres(const clockid_t which_clock, struct timespec *tp) }
static struct k_clock sgi_clock = { - .clock_set = sgi_clock_set, - .clock_get = sgi_clock_get, - .clock_getres = sgi_clock_getres, + .clock_set64 = sgi_clock_set, + .clock_get64 = sgi_clock_get, + .clock_getres64 = sgi_clock_getres, .timer_create = sgi_timer_create, - .timer_set = sgi_timer_set, + .timer_set64 = sgi_timer_set, .timer_del = sgi_timer_del, - .timer_get = sgi_timer_get + .timer_get64 = sgi_timer_get };
/**
This patch changes to the new methods with timespec64/itimerspec64 type of k_clock structure, and converts the timespec/itimerspec type to timespec64/itimerspec64 typein alarmtimer.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/alarmtimer.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 1b001ed..68186e1 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -489,35 +489,36 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, /** * alarm_clock_getres - posix getres interface * @which_clock: clockid - * @tp: timespec to fill + * @tp: timespec64 to fill * * Returns the granularity of underlying alarm base clock */ -static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp) +static int alarm_clock_getres(const clockid_t which_clock, + struct timespec64 *tp) { clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid;
if (!alarmtimer_get_rtcdev()) return -EINVAL;
- return hrtimer_get_res(baseid, tp); + return hrtimer_get_res64(baseid, tp); }
/** * alarm_clock_get - posix clock_get interface * @which_clock: clockid - * @tp: timespec to fill. + * @tp: timespec64 to fill. * * Provides the underlying alarm base time. */ -static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) +static int alarm_clock_get(clockid_t which_clock, struct timespec64 *tp) { struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)];
if (!alarmtimer_get_rtcdev()) return -EINVAL;
- *tp = ktime_to_timespec(base->gettime()); + *tp = ktime_to_timespec64(base->gettime()); return 0; }
@@ -547,24 +548,24 @@ static int alarm_timer_create(struct k_itimer *new_timer) /** * alarm_timer_get - posix timer_get interface * @new_timer: k_itimer pointer - * @cur_setting: itimerspec data to fill + * @cur_setting: itimerspec64 data to fill * * Copies out the current itimerspec data */ static void alarm_timer_get(struct k_itimer *timr, - struct itimerspec *cur_setting) + struct itimerspec64 *cur_setting) { ktime_t relative_expiry_time = alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
if (ktime_to_ns(relative_expiry_time) > 0) { - cur_setting->it_value = ktime_to_timespec(relative_expiry_time); + cur_setting->it_value = ktime_to_timespec64(relative_expiry_time); } else { cur_setting->it_value.tv_sec = 0; cur_setting->it_value.tv_nsec = 0; }
- cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval); + cur_setting->it_interval = ktime_to_timespec64(timr->it.alarm.interval); }
/** @@ -588,14 +589,14 @@ static int alarm_timer_del(struct k_itimer *timr) * alarm_timer_set - posix timer_set interface * @timr: k_itimer pointer to be deleted * @flags: timer flags - * @new_setting: itimerspec to be used - * @old_setting: itimerspec being replaced + * @new_setting: itimerspec64 to be used + * @old_setting: itimerspec64 being replaced * * Sets the timer to new_setting, and starts the timer. */ static int alarm_timer_set(struct k_itimer *timr, int flags, - struct itimerspec *new_setting, - struct itimerspec *old_setting) + struct itimerspec64 *new_setting, + struct itimerspec64 *old_setting) { ktime_t exp;
@@ -613,8 +614,8 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, return TIMER_RETRY;
/* start the timer */ - timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); - exp = timespec_to_ktime(new_setting->it_value); + timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval); + exp = timespec64_to_ktime(new_setting->it_value); /* Convert (if necessary) to absolute time */ if (flags != TIMER_ABSTIME) { ktime_t now; @@ -670,7 +671,7 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
/** - * update_rmtp - Update remaining timespec value + * update_rmtp - Update remaining timespec64 value * @exp: expiration time * @type: timer type * @rmtp: user pointer to remaining timepsec value @@ -824,12 +825,12 @@ static int __init alarmtimer_init(void) int error = 0; int i; struct k_clock alarm_clock = { - .clock_getres = alarm_clock_getres, - .clock_get = alarm_clock_get, + .clock_getres64 = alarm_clock_getres, + .clock_get64 = alarm_clock_get, .timer_create = alarm_timer_create, - .timer_set = alarm_timer_set, + .timer_set64 = alarm_timer_set, .timer_del = alarm_timer_del, - .timer_get = alarm_timer_get, + .timer_get64 = alarm_timer_get, .nsleep = alarm_timer_nsleep, };
This patch converts the posix clock operations over to the new methods with timespec64/itimerspec64 type to making them ready for 2038, and it is based on the ptp patch series.
And also changes to the 64bit methods for k_clock structure, that converts the timespec/itimerspec type to timespec64/itimerspec64 type.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- drivers/ptp/ptp_clock.c | 26 ++++++++------------------ include/linux/posix-clock.h | 10 +++++----- kernel/time/posix-clock.c | 20 ++++++++++---------- 3 files changed, 23 insertions(+), 33 deletions(-)
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index bee8270..8c086e7 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -97,32 +97,24 @@ static s32 scaled_ppm_to_ppb(long ppm)
/* posix clock implementation */
-static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp) +static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp) { tp->tv_sec = 0; tp->tv_nsec = 1; return 0; }
-static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp) +static int ptp_clock_settime(struct posix_clock *pc, + const struct timespec64 *tp) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); - struct timespec64 ts = timespec_to_timespec64(*tp); - - return ptp->info->settime64(ptp->info, &ts); + return ptp->info->settime64(ptp->info, tp); }
-static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp) +static int ptp_clock_gettime(struct posix_clock *pc, struct timespec64 *tp) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); - struct timespec64 ts; - int err; - - err = ptp->info->gettime64(ptp->info, &ts); - if (!err) - *tp = timespec64_to_timespec(ts); - - return err; + return ptp->info->gettime64(ptp->info, tp); }
static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) @@ -134,8 +126,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) ops = ptp->info;
if (tx->modes & ADJ_SETOFFSET) { - struct timespec ts; - ktime_t kt; + struct timespec64 ts; s64 delta;
ts.tv_sec = tx->time.tv_sec; @@ -147,8 +138,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC) return -EINVAL;
- kt = timespec_to_ktime(ts); - delta = ktime_to_ns(kt); + delta = timespec64_to_ns(&ts); err = ops->adjtime(ops, delta); } else if (tx->modes & ADJ_FREQUENCY) { s32 ppb = scaled_ppm_to_ppb(tx->freq); diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h index 34c4498..fd7e22c 100644 --- a/include/linux/posix-clock.h +++ b/include/linux/posix-clock.h @@ -59,23 +59,23 @@ struct posix_clock_operations {
int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
- int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts); + int (*clock_gettime)(struct posix_clock *pc, struct timespec64 *ts);
- int (*clock_getres) (struct posix_clock *pc, struct timespec *ts); + int (*clock_getres)(struct posix_clock *pc, struct timespec64 *ts);
int (*clock_settime)(struct posix_clock *pc, - const struct timespec *ts); + const struct timespec64 *ts);
int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
void (*timer_gettime)(struct posix_clock *pc, - struct k_itimer *kit, struct itimerspec *tsp); + struct k_itimer *kit, struct itimerspec64 *tsp);
int (*timer_settime)(struct posix_clock *pc, struct k_itimer *kit, int flags, - struct itimerspec *tsp, struct itimerspec *old); + struct itimerspec64 *tsp, struct itimerspec64 *old); /* * Optional character device methods: */ diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index ce033c7..e21e4c1 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -297,7 +297,7 @@ out: return err; }
-static int pc_clock_gettime(clockid_t id, struct timespec *ts) +static int pc_clock_gettime(clockid_t id, struct timespec64 *ts) { struct posix_clock_desc cd; int err; @@ -316,7 +316,7 @@ static int pc_clock_gettime(clockid_t id, struct timespec *ts) return err; }
-static int pc_clock_getres(clockid_t id, struct timespec *ts) +static int pc_clock_getres(clockid_t id, struct timespec64 *ts) { struct posix_clock_desc cd; int err; @@ -335,7 +335,7 @@ static int pc_clock_getres(clockid_t id, struct timespec *ts) return err; }
-static int pc_clock_settime(clockid_t id, const struct timespec *ts) +static int pc_clock_settime(clockid_t id, const struct timespec64 *ts) { struct posix_clock_desc cd; int err; @@ -399,7 +399,7 @@ static int pc_timer_delete(struct k_itimer *kit) return err; }
-static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) +static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec64 *ts) { clockid_t id = kit->it_clock; struct posix_clock_desc cd; @@ -414,7 +414,7 @@ static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) }
static int pc_timer_settime(struct k_itimer *kit, int flags, - struct itimerspec *ts, struct itimerspec *old) + struct itimerspec64 *ts, struct itimerspec64 *old) { clockid_t id = kit->it_clock; struct posix_clock_desc cd; @@ -435,12 +435,12 @@ static int pc_timer_settime(struct k_itimer *kit, int flags, }
struct k_clock clock_posix_dynamic = { - .clock_getres = pc_clock_getres, - .clock_set = pc_clock_settime, - .clock_get = pc_clock_gettime, + .clock_getres64 = pc_clock_getres, + .clock_set64 = pc_clock_settime, + .clock_get64 = pc_clock_gettime, .clock_adj = pc_clock_adjtime, .timer_create = pc_timer_create, - .timer_set = pc_timer_settime, + .timer_set64 = pc_timer_settime, .timer_del = pc_timer_delete, - .timer_get = pc_timer_gettime, + .timer_get64 = pc_timer_gettime, };
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
This patch changes to the new methods of k_clock structure with timespec64 type, converts the timespec/itimerspec type to timespec64/itimerspec64 type for the callback function in posix-cpu-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-cpu-timers.c | 83 +++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 39 deletions(-)
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 0075da7..51cfead 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -52,7 +52,7 @@ static int check_clock(const clockid_t which_clock) }
static inline unsigned long long -timespec_to_sample(const clockid_t which_clock, const struct timespec *tp) +timespec64_to_sample(const clockid_t which_clock, const struct timespec64 *tp) { unsigned long long ret;
@@ -60,19 +60,19 @@ timespec_to_sample(const clockid_t which_clock, const struct timespec *tp) if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { ret = (unsigned long long)tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec; } else { - ret = cputime_to_expires(timespec_to_cputime(tp)); + ret = cputime_to_expires(timespec64_to_cputime(tp)); } return ret; }
-static void sample_to_timespec(const clockid_t which_clock, +static void sample_to_timespec64(const clockid_t which_clock, unsigned long long expires, - struct timespec *tp) + struct timespec64 *tp) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) - *tp = ns_to_timespec(expires); + *tp = ns_to_timespec64(expires); else - cputime_to_timespec((__force cputime_t)expires, tp); + cputime_to_timespec64((__force cputime_t)expires, tp); }
/* @@ -141,7 +141,7 @@ static inline unsigned long long virt_ticks(struct task_struct *p) }
static int -posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp) +posix_cpu_clock_getres(const clockid_t which_clock, struct timespec64 *tp) { int error = check_clock(which_clock); if (!error) { @@ -160,7 +160,7 @@ posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp) }
static int -posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp) +posix_cpu_clock_set(const clockid_t which_clock, const struct timespec64 *tp) { /* * You can never reset a CPU clock, but we check for other errors @@ -263,7 +263,7 @@ static int cpu_clock_sample_group(const clockid_t which_clock,
static int posix_cpu_clock_get_task(struct task_struct *tsk, const clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { int err = -EINVAL; unsigned long long rtn; @@ -277,13 +277,14 @@ static int posix_cpu_clock_get_task(struct task_struct *tsk, }
if (!err) - sample_to_timespec(which_clock, rtn, tp); + sample_to_timespec64(which_clock, rtn, tp);
return err; }
-static int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp) +static int posix_cpu_clock_get(const clockid_t which_clock, + struct timespec64 *tp) { const pid_t pid = CPUCLOCK_PID(which_clock); int err = -EINVAL; @@ -598,7 +599,7 @@ static inline void posix_cpu_timer_kick_nohz(void) { } * and try again. (This happens when the timer is in the middle of firing.) */ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, - struct itimerspec *new, struct itimerspec *old) + struct itimerspec64 *new, struct itimerspec64 *old) { unsigned long flags; struct sighand_struct *sighand; @@ -608,7 +609,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
WARN_ON_ONCE(p == NULL);
- new_expires = timespec_to_sample(timer->it_clock, &new->it_value); + new_expires = timespec64_to_sample(timer->it_clock, &new->it_value);
/* * Protect against sighand release/switch in exit/exec and p->cpu_timers @@ -669,7 +670,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, bump_cpu_timer(timer, val); if (val < timer->it.cpu.expires) { old_expires = timer->it.cpu.expires - val; - sample_to_timespec(timer->it_clock, + sample_to_timespec64(timer->it_clock, old_expires, &old->it_value); } else { @@ -709,7 +710,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, * Install the new reload setting, and * set up the signal and overrun bookkeeping. */ - timer->it.cpu.incr = timespec_to_sample(timer->it_clock, + timer->it.cpu.incr = timespec64_to_sample(timer->it_clock, &new->it_interval);
/* @@ -734,7 +735,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, ret = 0; out: if (old) { - sample_to_timespec(timer->it_clock, + sample_to_timespec64(timer->it_clock, old_incr, &old->it_interval); } if (!ret) @@ -742,7 +743,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, return ret; }
-static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) +static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp) { unsigned long long now; struct task_struct *p = timer->it.cpu.task; @@ -752,7 +753,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) /* * Easy part: convert the reload time. */ - sample_to_timespec(timer->it_clock, + sample_to_timespec64(timer->it_clock, timer->it.cpu.incr, &itp->it_interval);
if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */ @@ -782,7 +783,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) * Call the timer disarmed, nothing else to do. */ timer->it.cpu.expires = 0; - sample_to_timespec(timer->it_clock, timer->it.cpu.expires, + sample_to_timespec64(timer->it_clock, timer->it.cpu.expires, &itp->it_value); } else { cpu_timer_sample_group(timer->it_clock, p, &now); @@ -791,7 +792,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) }
if (now < timer->it.cpu.expires) { - sample_to_timespec(timer->it_clock, + sample_to_timespec64(timer->it_clock, timer->it.cpu.expires - now, &itp->it_value); } else { @@ -1248,6 +1249,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, struct timespec *rqtp, struct itimerspec *it) { struct k_itimer timer; + struct timespec64 ts64; + struct itimerspec64 *it64; int error;
/* @@ -1260,13 +1263,14 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, error = posix_cpu_timer_create(&timer); timer.it_process = current; if (!error) { - static struct itimerspec zero_it; + static struct itimerspec64 zero_it;
memset(it, 0, sizeof *it); it->it_value = *rqtp;
spin_lock_irq(&timer.it_lock); - error = posix_cpu_timer_set(&timer, flags, it, NULL); + *it64 = itimerspec_to_itimerspec64(*it); + error = posix_cpu_timer_set(&timer, flags, it64, NULL); if (error) { spin_unlock_irq(&timer.it_lock); return error; @@ -1295,8 +1299,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, /* * We were interrupted by a signal. */ - sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); - error = posix_cpu_timer_set(&timer, 0, &zero_it, it); + sample_to_timespec64(which_clock, timer.it.cpu.expires, &ts64); + *rqtp = timespec64_to_timespec(ts64); + error = posix_cpu_timer_set(&timer, 0, &zero_it, it64); if (!error) { /* * Timer is now unarmed, deletion can not fail. @@ -1395,12 +1400,12 @@ static long posix_cpu_nsleep_restart(struct restart_block *restart_block) #define THREAD_CLOCK MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED)
static int process_cpu_clock_getres(const clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { return posix_cpu_clock_getres(PROCESS_CLOCK, tp); } static int process_cpu_clock_get(const clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { return posix_cpu_clock_get(PROCESS_CLOCK, tp); } @@ -1420,12 +1425,12 @@ static long process_cpu_nsleep_restart(struct restart_block *restart_block) return -EINVAL; } static int thread_cpu_clock_getres(const clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { return posix_cpu_clock_getres(THREAD_CLOCK, tp); } static int thread_cpu_clock_get(const clockid_t which_clock, - struct timespec *tp) + struct timespec64 *tp) { return posix_cpu_clock_get(THREAD_CLOCK, tp); } @@ -1436,37 +1441,37 @@ static int thread_cpu_timer_create(struct k_itimer *timer) }
struct k_clock clock_posix_cpu = { - .clock_getres = posix_cpu_clock_getres, - .clock_set = posix_cpu_clock_set, - .clock_get = posix_cpu_clock_get, + .clock_getres64 = posix_cpu_clock_getres, + .clock_set64 = posix_cpu_clock_set, + .clock_get64 = posix_cpu_clock_get, .timer_create = posix_cpu_timer_create, .nsleep = posix_cpu_nsleep, .nsleep_restart = posix_cpu_nsleep_restart, - .timer_set = posix_cpu_timer_set, + .timer_set64 = posix_cpu_timer_set, .timer_del = posix_cpu_timer_del, - .timer_get = posix_cpu_timer_get, + .timer_get64 = posix_cpu_timer_get, };
static __init int init_posix_cpu_timers(void) { struct k_clock process = { - .clock_getres = process_cpu_clock_getres, - .clock_get = process_cpu_clock_get, + .clock_getres64 = process_cpu_clock_getres, + .clock_get64 = process_cpu_clock_get, .timer_create = process_cpu_timer_create, .nsleep = process_cpu_nsleep, .nsleep_restart = process_cpu_nsleep_restart, }; struct k_clock thread = { - .clock_getres = thread_cpu_clock_getres, - .clock_get = thread_cpu_clock_get, + .clock_getres64 = thread_cpu_clock_getres, + .clock_get64 = thread_cpu_clock_get, .timer_create = thread_cpu_timer_create, }; - struct timespec ts; + struct timespec64 ts;
posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process); posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
- cputime_to_timespec(cputime_one_jiffy, &ts); + cputime_to_timespec64(cputime_one_jiffy, &ts); onecputick = ts.tv_nsec; WARN_ON(ts.tv_sec != 0);
All of the k_clock users have been converted to the new methods. This patch removes the older methods with timepsec/itimerspec type. As a result, the k_clock structure is ready for the year 2038.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 9 ------ kernel/time/posix-timers.c | 72 +++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 52 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 35786c5..7c3dae2 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -97,29 +97,20 @@ struct k_itimer { };
struct k_clock { - int (*clock_getres) (const clockid_t which_clock, struct timespec *tp); int (*clock_getres64) (const clockid_t which_clock, struct timespec64 *tp); - int (*clock_set) (const clockid_t which_clock, - const struct timespec *tp); int (*clock_set64) (const clockid_t which_clock, const struct timespec64 *tp); - int (*clock_get) (const clockid_t which_clock, struct timespec * tp); int (*clock_get64) (const clockid_t which_clock, struct timespec64 *tp); int (*clock_adj) (const clockid_t which_clock, struct timex *tx); int (*timer_create) (struct k_itimer *timer); int (*nsleep) (const clockid_t which_clock, int flags, struct timespec *, struct timespec __user *); long (*nsleep_restart) (struct restart_block *restart_block); - int (*timer_set) (struct k_itimer * timr, int flags, - struct itimerspec * new_setting, - struct itimerspec * old_setting); int (*timer_set64) (struct k_itimer *timr, int flags, struct itimerspec64 *new_setting, struct itimerspec64 *old_setting); int (*timer_del) (struct k_itimer * timr); #define TIMER_RETRY 1 - void (*timer_get) (struct k_itimer * timr, - struct itimerspec * cur_setting); void (*timer_get64) (struct k_itimer *timr, struct itimerspec64 *cur_setting); }; diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 47d1abf..3196ec0 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -528,13 +528,13 @@ void posix_timers_register_clock(const clockid_t clock_id, return; }
- if (!new_clock->clock_get && !new_clock->clock_get64) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_get() and clock_get64()\n", + if (!new_clock->clock_get64) { + printk(KERN_WARNING "POSIX clock id %d lacks clock_get64()\n", clock_id); return; } - if (!new_clock->clock_getres && !new_clock->clock_getres64) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_getres() and clock_getres64()\n", + if (!!new_clock->clock_getres64) { + printk(KERN_WARNING "POSIX clock id %d lacks clock_getres64()\n", clock_id); return; } @@ -585,7 +585,7 @@ static struct k_clock *clockid_to_kclock(const clockid_t id) return (id & CLOCKFD_MASK) == CLOCKFD ? &clock_posix_dynamic : &clock_posix_cpu;
- if (id >= MAX_CLOCKS || (!posix_clocks[id].clock_getres && !posix_clocks[id].clock_getres64)) + if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres64) return NULL; return &posix_clocks[id]; } @@ -788,15 +788,11 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || (!kc->timer_get && !kc->timer_get64))) { + if (WARN_ON_ONCE(!kc || !kc->timer_get64)) { ret = -EINVAL; } else { - if (kc->timer_get64) { - kc->timer_get64(timr, &cur_setting64); - cur_setting = itimerspec64_to_itimerspec(cur_setting64); - } else { - kc->timer_get(timr, &cur_setting); - } + kc->timer_get64(timr, &cur_setting64); + cur_setting = itimerspec64_to_itimerspec(cur_setting64); }
unlock_timer(timr, flags); @@ -911,18 +907,14 @@ retry: return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || (!kc->timer_set && !kc->timer_set64))) { + if (WARN_ON_ONCE(!kc || !kc->timer_set64)) { error = -EINVAL; } else { - if (kc->timer_set64) { - new_spec64 = itimerspec_to_itimerspec64(new_spec); - error = kc->timer_set64(timr, flags, &new_spec64, - &old_spec64); - if (old_setting) - old_spec = itimerspec64_to_itimerspec(old_spec64); - } else { - error = kc->timer_set(timr, flags, &new_spec, rtn); - } + new_spec64 = itimerspec_to_itimerspec64(new_spec); + error = kc->timer_set64(timr, flags, &new_spec64, + &old_spec64); + if (old_setting) + old_spec = itimerspec64_to_itimerspec(old_spec64); }
unlock_timer(timr, flag); @@ -1032,18 +1024,14 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, struct timespec new_tp; struct timespec64 new_tp64;
- if (!kc || (!kc->clock_set && !kc->clock_set64)) + if (!kc || !kc->clock_set64) return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
- if (kc->clock_set64) { - new_tp64 = timespec_to_timespec64(new_tp); - return kc->clock_set64(which_clock, &new_tp64); - } else { - return kc->clock_set(which_clock, &new_tp); - } + new_tp64 = timespec_to_timespec64(new_tp); + return kc->clock_set64(which_clock, &new_tp64); }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, @@ -1057,14 +1045,13 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, if (!kc) return -EINVAL;
- if (kc->clock_get64) { - error = kc->clock_get64(which_clock, &kernel_tp64); - kernel_tp = timespec64_to_timespec(kernel_tp64); - } else { - error = kc->clock_get(which_clock, &kernel_tp); - } + error = kc->clock_get64(which_clock, &kernel_tp64); + if (!error) + return error; + + kernel_tp = timespec64_to_timespec(kernel_tp64);
- if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) + if (copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) error = -EFAULT;
return error; @@ -1104,14 +1091,13 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, if (!kc) return -EINVAL;
- if (kc->clock_getres64) { - error = kc->clock_getres64(which_clock, &rtn_tp64); - rtn_tp = timespec64_to_timespec(rtn_tp64); - } else { - error = kc->clock_getres(which_clock, &rtn_tp); - } + error = kc->clock_getres64(which_clock, &rtn_tp64); + if (!error) + return error; + + rtn_tp = timespec64_to_timespec(rtn_tp64);
- if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) + if (tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) error = -EFAULT;
return error;
On Friday 17 April 2015 14:47:07 Baolin Wang wrote:
This patch series change the 32-bit time type (timespec/itimerspec) to the 64-bit one (timespec64/itimerspec64), since 32-bit time types will break in the year 2038.
This patch series introduce new methods with timespec64/itimerspec64 type, and remove the old ones with timespec/itimerspec type for posix_clock_operations and k_clock structure.
Changes since v4: - Modify the conversion between the itimerspec64 and itimerspec for 64bit. - Continue to split up and merge the patch. - Explain more for the patch log. - Re-order the patch of the patch series.
Next step will replace the other callback pointers of k_clock structure.
Looks very nice overall now. I had one last comment for the modifications in patch 1, but it's only for style, not correctness. We also had one last change for patch 9, based on your other questions. Please address them both, then send the series again and take the maintainer for this code (Thomas Gleixner tglx@linutronix.de) as well as the linux-kernel@vger.kernel.org list on Cc. There will probably be some more comments, but I think overall the approach and the implementation are both sensible now.
Arnd