This patch series changes the 32-bit time types (timespec/itimerspec) to the 64-bit types (timespec64/itimerspec64), since 32-bit time types will break in the year 2038.
This patch series introduces new methods with timespec64/itimerspec64 type, and removes the old ones with timespec/itimerspec type for posix_clock_operations and k_clock structure.
timekeeping: Introduce struct itimerspec64. timekeeping: Introduce current_kernel_time64(). timekeeping: Change timekeeping_clocktai() with timespec64 type. hrtimer: Introduce hrtimer_get_res64(). security: Introduce security_settime64(). time: Introduce do_sys_settimeofday64(). time: Introduce jiffies_to_timespec64()/timespec64_to_jiffies(). cputime: Introduce cputime_to_timespec64()/timespec64_to_cputime(). posix-timers: Split up timer_gettime()/timer_settime()/clock_settime()/ clock_gettime()/clock_getres(). posix-timers: Convert timer_gettime()/timer_settime()/clock_settime()/ clock_gettime()/clock_getres() to timespec64/itimerspec64. mmtimer: Convert to timespec64/itimerspec64. alarmtimer: Convert to timespec64/itimerspec64. posix-clock: Convert to timespec64/itimerspec64. posix-cpu-timers: Convert to timespec64/itimerspec64.
Baolin Wang (24): 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 security/security: Introduce security_settime64() function with timespec64 type time:Introduce the do_sys_settimeofday64() function with timespec64 type posix-timers:Change the implementation for timer_gettime syscall function posix-timers:Convert to the 64bit methods for the timer_gettime syscall function posix-timers:Change the implementation for timer_settime syscall posix-timers:Convert to the 64bit methods for the timer_settime syscall function posix-timers:Change the implementation for clock_settime syscall function posix-timers:Convert to the 64bit methods for the clock_settime syscall function posix-timers:Change the implementation for clock_gettime syscall function posix-timers:Convert to the 64bit methods for the clock_gettime syscall function posix-timers:Change the implementation for clock_getres syscall function posix-timers:Convert to the 64bit methods for the clock_getres syscall function timekeeping:Introduce the timekeeping_clocktai() function with timespec64 type time/posix-timers:Convert to the 64bit methods for k_clock callback functions char/mmtimer:Convert to the 64bit methods for k_clock callback functions time/alarmtimer:Convert to the new 64bit methods for k_clock structure time/posix-clock:Convert to the 64bit methods for k_clock and posix_clock_operations structure time/time:Introduce the timespec64_to_jiffies()/jiffies_to_timespec64() function 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/itimerspec type
arch/powerpc/include/asm/cputime.h | 6 +- arch/s390/include/asm/cputime.h | 8 +- drivers/char/mmtimer.c | 36 +++-- drivers/ptp/ptp_clock.c | 26 +--- include/asm-generic/cputime_jiffies.h | 10 +- include/asm-generic/cputime_nsecs.h | 4 +- include/linux/cputime.h | 15 ++ include/linux/hrtimer.h | 12 +- include/linux/jiffies.h | 21 ++- include/linux/posix-clock.h | 10 +- include/linux/posix-timers.h | 18 +-- include/linux/security.h | 25 ++- include/linux/time64.h | 35 +++++ include/linux/timekeeping.h | 26 +++- 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 | 270 ++++++++++++++++++++++----------- kernel/time/time.c | 20 +-- kernel/time/timekeeping.c | 6 +- kernel/time/timekeeping.h | 1 - security/commoncap.c | 2 +- security/security.c | 2 +- 24 files changed, 447 insertions(+), 262 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(), that makes itimerspec ready for 2038 year.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/time64.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/include/linux/time64.h b/include/linux/time64.h index a383147..61dc4cb 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -11,11 +11,18 @@ typedef __s64 time64_t; */ #if __BITS_PER_LONG == 64 # define timespec64 timespec +#define itimerspec64 itimerspec #else struct timespec64 { time64_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; + +struct itimerspec64 { + struct timespec64 it_interval; /* timer period */ + struct timespec64 it_value; /* timer expiration */ +}; + #endif
/* Parameters used to convert the timespec values: */ @@ -43,6 +50,16 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) return ts; }
+static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64) +{ + return *its64; +} + +static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its) +{ + return *its; +} + # define timespec64_equal timespec_equal # define timespec64_compare timespec_compare # define set_normalized_timespec64 set_normalized_timespec @@ -75,6 +92,24 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) return ret; }
+static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64) +{ + struct itimerspec ret; + + ret.it_interval = timespec64_to_timespec(its64->it_interval); + ret.it_value = timespec64_to_timespec(its64->it_value); + return ret; +} + +static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its) +{ + struct itimerspec64 ret; + + ret.it_interval = timespec_to_timespec64(its->it_interval); + ret.it_value = timespec_to_timespec64(its->it_value); + return ret; +} + static inline int timespec64_equal(const struct timespec64 *a, const struct timespec64 *b) {
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) {
For introducing the do_sys_settimeofday64() function with timespec64 type to make it ready for 2038 issue, it need to introduce the security_settime64() function with timespec64 type firstly.
Also introduce a default security_settime64() function with timespec64 type when it hasn't defined the CONFIG_SECURITY macro.
Also this patch changes the "settime" pointer's argument with timespec64 type in security_operations structure for introducing the the security_settime64() function.
Meanwhile moves the security_settime() defined in security/security.c file to include/linux/security.h file as a static function, that makes it convenient to delete the security_settime() later.
And change the cap_settime() function's argument with timespec64 type to make it ready for 2038 issue, which is only used by security_settime64()/security_settime() function.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/security.h | 25 ++++++++++++++++++++----- security/commoncap.c | 2 +- security/security.c | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h index a1b7dbd..5288794 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -75,7 +75,7 @@ struct timezone; */ extern int cap_capable(const struct cred *cred, struct user_namespace *ns, int cap, int audit); -extern int cap_settime(const struct timespec *ts, const struct timezone *tz); +extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); @@ -1353,7 +1353,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Return 0 if permission is granted. * @settime: * Check permission to change the system time. - * struct timespec and timezone are defined in include/linux/time.h + * struct timespec64 is defined in include/linux/time64.h and timezone is + * defined in include/linux/time.h * @ts contains new time * @tz contains new timezone * Return 0 if permission is granted. @@ -1483,7 +1484,7 @@ struct security_operations { int (*quotactl) (int cmds, int type, int id, struct super_block *sb); int (*quota_on) (struct dentry *dentry); int (*syslog) (int type); - int (*settime) (const struct timespec *ts, const struct timezone *tz); + int (*settime) (const struct timespec64 *ts, const struct timezone *tz); int (*vm_enough_memory) (struct mm_struct *mm, long pages);
int (*bprm_set_creds) (struct linux_binprm *bprm); @@ -1790,7 +1791,13 @@ int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); -int security_settime(const struct timespec *ts, const struct timezone *tz); +int security_settime64(const struct timespec64 *ts, const struct timezone *tz); +static int security_settime(const struct timespec *ts, const struct timezone *tz) +{ + struct timespec64 ts64 = timespec_to_timespec64(*ts); + + return security_settime64(&ts64, tz); +} int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); @@ -2040,10 +2047,18 @@ static inline int security_syslog(int type) return 0; }
+static inline int security_settime64(const struct timespec64 *ts, + const struct timezone *tz) +{ + return cap_settime(ts, tz); +} + static inline int security_settime(const struct timespec *ts, const struct timezone *tz) { - return cap_settime(ts, tz); + struct timsepc64 ts64 = timespec_to_timespec64(*ts); + + return cap_settime(&ts64, tz); }
static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) diff --git a/security/commoncap.c b/security/commoncap.c index f66713b..bdb8ec0 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -116,7 +116,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, * Determine whether the current process may set the system clock and timezone * information, returning 0 if permission granted, -ve if denied. */ -int cap_settime(const struct timespec *ts, const struct timezone *tz) +int cap_settime(const struct timespec64 *ts, const struct timezone *tz) { if (!capable(CAP_SYS_TIME)) return -EPERM; diff --git a/security/security.c b/security/security.c index e81d5bb..0be5032 100644 --- a/security/security.c +++ b/security/security.c @@ -224,7 +224,7 @@ int security_syslog(int type) return security_ops->syslog(type); }
-int security_settime(const struct timespec *ts, const struct timezone *tz) +int security_settime64(const struct timespec64 *ts, const struct timezone *tz) { return security_ops->settime(ts, tz); }
Introduce the do_sys_settimeofday64() function with timespec64 type to make it is ready for 2038 issue when setting the time of day.
And move the do_sys_settimeofday() function to the timekeeping.h file, that it is convenient to delete it later.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/timekeeping.h | 12 ++++++++++-- kernel/time/time.c | 8 ++++---- 2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index c6d5ae9..89beb62 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -11,8 +11,16 @@ extern int timekeeping_suspended; */ extern void do_gettimeofday(struct timeval *tv); extern int do_settimeofday64(const struct timespec64 *ts); -extern int do_sys_settimeofday(const struct timespec *tv, - const struct timezone *tz); +extern int do_sys_settimeofday64(const struct timespec64 *tv, + const struct timezone *tz); +static inline int do_sys_settimeofday(const struct timespec *tv, + const struct timezone *tz) +{ + struct timespec64 ts64; + + ts64 = timespec_to_timespec64(*tv); + return do_sys_settimeofday64(&ts64, tz); +}
/* * Kernel time accessors diff --git a/kernel/time/time.c b/kernel/time/time.c index 2c85b77..33c539b 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -160,15 +160,15 @@ static inline void warp_clock(void) * various programs will get confused when the clock gets warped. */
-int do_sys_settimeofday(const struct timespec *tv, const struct timezone *tz) +int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz) { static int firsttime = 1; int error = 0;
- if (tv && !timespec_valid(tv)) + if (tv && !timespec64_valid(tv)) return -EINVAL;
- error = security_settime(tv, tz); + error = security_settime64(tv, tz); if (error) return error;
@@ -182,7 +182,7 @@ int do_sys_settimeofday(const struct timespec *tv, const struct timezone *tz) } } if (tv) - return do_settimeofday(tv); + return do_settimeofday64(tv); return 0; }
This patch splits out the guts of the timer_gettime syscall and changes the timer_gettime syscall implementation to prepare the converting to 64bit methods for the timer_gettime syscall function in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 31ea01f..9df664a 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -766,11 +766,8 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) cur_setting->it_value = ktime_to_timespec(remaining); }
-/* Get the time remaining on a POSIX.1b interval timer. */ -SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, - struct itimerspec __user *, setting) +static int __timer_gettime(timer_t timer_id, struct itimerspec *cur_setting) { - struct itimerspec cur_setting; struct k_itimer *timr; struct k_clock *kc; unsigned long flags; @@ -784,9 +781,18 @@ SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, if (WARN_ON_ONCE(!kc || !kc->timer_get)) ret = -EINVAL; else - kc->timer_get(timr, &cur_setting); + kc->timer_get(timr, cur_setting);
unlock_timer(timr, flags); + return ret; +} + +/* Get the time remaining on a POSIX.1b interval timer. */ +SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, + struct itimerspec __user *, setting) +{ + struct itimerspec cur_setting; + int ret = __timer_gettime(timer_id, &cur_setting);
if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) return -EFAULT;
This patch introduces the timer_get64 method with itimerspec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with itimerspec64 type for the timer_gettime syscall function, and change the timer_gettime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the timer_get64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 2 ++ kernel/time/posix-timers.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 907f3fd..e84436b 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -113,6 +113,8 @@ struct k_clock { #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 9df664a..91036b1 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -140,6 +140,7 @@ static int common_timer_del(struct k_itimer *timer); static enum hrtimer_restart posix_timer_fn(struct hrtimer *data);
static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags); +static struct k_clock *clockid_to_kclock(const clockid_t id);
#define lock_timer(tid, flags) \ ({ struct k_itimer *__timr; \ @@ -513,6 +514,16 @@ static struct pid *good_sigevent(sigevent_t * event) return task_pid(rtn); }
+static void default_timer_get64(struct k_itimer *timr, + struct itimerspec64 *cur_setting64) +{ + struct itimerspec cur_setting; + struct k_clock *kc = clockid_to_kclock(timr->it_clock); + + kc->timer_get(timr, &cur_setting); + *cur_setting64 = itimerspec_to_itimerspec64(&cur_setting); +} + void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -533,6 +544,9 @@ void posix_timers_register_clock(const clockid_t clock_id, return; }
+ if (new_clock->timer_get && !new_clock->timer_get64) + new_clock->timer_get64 = default_timer_get64; + posix_clocks[clock_id] = *new_clock; } EXPORT_SYMBOL_GPL(posix_timers_register_clock); @@ -766,7 +780,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) cur_setting->it_value = ktime_to_timespec(remaining); }
-static int __timer_gettime(timer_t timer_id, struct itimerspec *cur_setting) +static int __timer_gettime(timer_t timer_id, struct itimerspec64 *cur_setting) { struct k_itimer *timr; struct k_clock *kc; @@ -778,10 +792,10 @@ static int __timer_gettime(timer_t timer_id, struct itimerspec *cur_setting) return -EINVAL;
kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || !kc->timer_get)) + if (WARN_ON_ONCE(!kc || !kc->timer_get64)) ret = -EINVAL; else - kc->timer_get(timr, cur_setting); + kc->timer_get64(timr, cur_setting);
unlock_timer(timr, flags); return ret; @@ -791,8 +805,17 @@ static int __timer_gettime(timer_t timer_id, struct itimerspec *cur_setting) SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, struct itimerspec __user *, setting) { - struct itimerspec cur_setting; +#ifdef CONFIG_64BIT + struct itimerspec64 cur_setting; int ret = __timer_gettime(timer_id, &cur_setting); +#else + struct itimerspec64 cur_setting64; + struct itimerspec cur_setting; + + int ret = __timer_gettime(timer_id, &cur_setting64); + if (!ret) + cur_setting = itimerspec64_to_itimerspec(&cur_setting64); +#endif
if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) return -EFAULT;
This patch splits out the guts of the timer_settime syscall and changes the timer_settime syscall implementation to prepare the converting to 64bit methods for the timer_settime syscall function in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 45 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 91036b1..d289846 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -899,27 +899,14 @@ common_timer_set(struct k_itimer *timr, int flags, return 0; }
-/* Set a POSIX.1b interval timer */ -SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - const struct itimerspec __user *, new_setting, - struct itimerspec __user *, old_setting) +static int __timer_settime(timer_t timer_id, int flags, struct itimerspec *new_spec, + struct itimerspec *old_spec) { struct k_itimer *timr; - struct itimerspec new_spec, old_spec; int error = 0; unsigned long flag; - struct itimerspec *rtn = old_setting ? &old_spec : NULL; struct k_clock *kc;
- if (!new_setting) - return -EINVAL; - - if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) - return -EFAULT; - - if (!timespec_valid(&new_spec.it_interval) || - !timespec_valid(&new_spec.it_value)) - return -EINVAL; retry: timr = lock_timer(timer_id, &flag); if (!timr) @@ -929,14 +916,38 @@ retry: if (WARN_ON_ONCE(!kc || !kc->timer_set)) error = -EINVAL; else - error = kc->timer_set(timr, flags, &new_spec, rtn); + error = kc->timer_set(timr, flags, new_spec, old_spec);
unlock_timer(timr, flag); if (error == TIMER_RETRY) { - rtn = NULL; // We already got the old time... + old_spec = NULL; // We already got the old time... goto retry; }
+ return error; +} + +/* Set a POSIX.1b interval timer */ +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, + const struct itimerspec __user *, new_setting, + struct itimerspec __user *, old_setting) +{ + struct itimerspec new_spec, old_spec; + int error = 0; + struct itimerspec *rtn = old_setting ? &old_spec : NULL; + + if (!new_setting) + return -EINVAL; + + if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) + return -EFAULT; + + if (!timespec_valid(&new_spec.it_interval) || + !timespec_valid(&new_spec.it_value)) + return -EINVAL; + + error = __timer_settime(timer_id, flags, &new_spec, rtn); + if (old_setting && !error && copy_to_user(old_setting, &old_spec, sizeof (old_spec))) error = -EFAULT;
On Tuesday 19 May 2015 20:49:49 Baolin Wang wrote:
+/* Set a POSIX.1b interval timer */ +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
const struct itimerspec __user *, new_setting,
struct itimerspec __user *, old_setting)
+{
struct itimerspec new_spec, old_spec;
int error = 0;
struct itimerspec *rtn = old_setting ? &old_spec : NULL;
if (!new_setting)
return -EINVAL;
if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
return -EFAULT;
if (!timespec_valid(&new_spec.it_interval) ||
!timespec_valid(&new_spec.it_value))
return -EINVAL;
error = __timer_settime(timer_id, flags, &new_spec, rtn);
if (old_setting && !error && copy_to_user(old_setting, &old_spec, sizeof (old_spec))) error = -EFAULT;
This part currently conflicts with my patch series that does the same thing slightly differently.
That is not a problem by itself, but it means that we have to coordinate a bit. One of us needs to get his patches merged first, so that the other one can rebase the other patches on top.
My patch for this is currently in drafting state, so it's possible that you should just go first, but please have a look at my implementation at http://git.kernel.org/cgit/linux/kernel/git/arnd/playground.git/commit/?h=y2...
I'm currently using a get_itimerspec() function there that copies a user space __kernel_itimerspec into a kernel-side itimerspec. There is also a get_timespec64() function I introduce, and in combination with your series, we should have a get_itimerspec64() as well as get_compat_itimerspec64() function.
I did not integrate the timespec_valid() part in there, but after looking at your code some more, I now think it would be good to combine them and have something like:
int get_itimerspec64(struct itimerspec64 *it, const struct __kernel_itimerspec __user *uit) { int ret
ret = get_timespec64(&it->it_interval, &uit->it_interval); if (ret) return ret;
return get_timespec64(&it->it_value, &uit->it_value); }
and add the timespec64_valid() check to get_timespec64().
Arnd
On 20 May 2015 at 21:39, Arnd Bergmann arnd@linaro.org wrote:
On Tuesday 19 May 2015 20:49:49 Baolin Wang wrote:
+/* Set a POSIX.1b interval timer */ +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
const struct itimerspec __user *, new_setting,
struct itimerspec __user *, old_setting)
+{
struct itimerspec new_spec, old_spec;
int error = 0;
struct itimerspec *rtn = old_setting ? &old_spec : NULL;
if (!new_setting)
return -EINVAL;
if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
return -EFAULT;
if (!timespec_valid(&new_spec.it_interval) ||
!timespec_valid(&new_spec.it_value))
return -EINVAL;
error = __timer_settime(timer_id, flags, &new_spec, rtn);
if (old_setting && !error && copy_to_user(old_setting, &old_spec, sizeof (old_spec))) error = -EFAULT;
This part currently conflicts with my patch series that does the same thing slightly differently.
That is not a problem by itself, but it means that we have to coordinate a bit. One of us needs to get his patches merged first, so that the other one can rebase the other patches on top.
My patch for this is currently in drafting state, so it's possible that you should just go first, but please have a look at my implementation at http://git.kernel.org/cgit/linux/kernel/git/arnd/playground.git/commit/?h=y2...
I'm currently using a get_itimerspec() function there that copies a user space __kernel_itimerspec into a kernel-side itimerspec. There is also a get_timespec64() function I introduce, and in combination with your series, we should have a get_itimerspec64() as well as get_compat_itimerspec64() function.
I did not integrate the timespec_valid() part in there, but after looking at your code some more, I now think it would be good to combine them and have something like:
int get_itimerspec64(struct itimerspec64 *it, const struct __kernel_itimerspec __user *uit) { int ret
ret = get_timespec64(&it->it_interval, &uit->it_interval); if (ret) return ret; return get_timespec64(&it->it_value, &uit->it_value);
}
and add the timespec64_valid() check to get_timespec64().
Arnd
Ok, got it. I should look at your implementation firstly and learn the concepts you introduce. Thanks.
This patch introduces the timer_set64 method with itimerspec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with itimerspec64 type for the timer_settime syscall function, and change the timer_settime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the timer_set64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 3 +++ kernel/time/posix-timers.c | 45 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index e84436b..16c3364 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -109,6 +109,9 @@ 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, diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index d289846..e0eb1fc 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -524,6 +524,23 @@ static void default_timer_get64(struct k_itimer *timr, *cur_setting64 = itimerspec_to_itimerspec64(&cur_setting); }
+static int default_timer_set64(struct k_itimer *timr, int flags, + struct itimerspec64 *new_setting64, + struct itimerspec64 *old_setting64) +{ + struct k_clock *kc = clockid_to_kclock(timr->it_clock); + struct itimerspec new_setting, old_setting; + struct itimerspec *rtn = old_setting64 ? &old_setting : NULL; + int ret; + + new_setting = itimerspec64_to_itimerspec(new_setting64); + ret = kc->timer_set(timr, flags, &new_setting, rtn); + if (!ret && old_setting64) + *old_setting64 = itimerspec_to_itimerspec64(&old_setting); + + return ret; +} + void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -546,6 +563,8 @@ void posix_timers_register_clock(const clockid_t clock_id,
if (new_clock->timer_get && !new_clock->timer_get64) new_clock->timer_get64 = default_timer_get64; + if (new_clock->timer_set && !new_clock->timer_set64) + new_clock->timer_set64 = default_timer_set64;
posix_clocks[clock_id] = *new_clock; } @@ -899,8 +918,8 @@ common_timer_set(struct k_itimer *timr, int flags, return 0; }
-static int __timer_settime(timer_t timer_id, int flags, struct itimerspec *new_spec, - struct itimerspec *old_spec) +static int __timer_settime(timer_t timer_id, int flags, struct itimerspec64 *new_spec, + struct itimerspec64 *old_spec) { struct k_itimer *timr; int error = 0; @@ -913,10 +932,10 @@ 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_set64)) error = -EINVAL; else - error = kc->timer_set(timr, flags, new_spec, old_spec); + error = kc->timer_set64(timr, flags, new_spec, old_spec);
unlock_timer(timr, flag); if (error == TIMER_RETRY) { @@ -932,9 +951,15 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, const struct itimerspec __user *, new_setting, struct itimerspec __user *, old_setting) { - struct itimerspec new_spec, old_spec; int error = 0; - struct itimerspec *rtn = old_setting ? &old_spec : NULL; +#ifdef CONFIG_64BIT + struct itimerspec64 new_spec, old_spec; + struct itimerspec64 *rtn = old_setting ? &old_spec : NULL; +#else + struct itimerspec new_spec, old_spec; + struct itimerspec64 new_spec64, old_spec64; + struct itimerspec64 *rtn64 = old_setting ? &old_spec64 : NULL; +#endif
if (!new_setting) return -EINVAL; @@ -946,7 +971,15 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, !timespec_valid(&new_spec.it_value)) return -EINVAL;
+#ifdef CONFIG_64BIT error = __timer_settime(timer_id, flags, &new_spec, rtn); +#else + new_spec64 = itimerspec_to_itimerspec64(&new_spec); + + error = __timer_settime(timer_id, flags, &new_spec64, rtn64); + if (!error && rtn64) + old_spec = itimerspec64_to_itimerspec(&old_spec64); +#endif
if (old_setting && !error && copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
This patch splits out the guts of the clock_settime syscall and changes the clock_settime syscall implementation to prepare the converting to 64bit methods for the clock_settime syscall function in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index e0eb1fc..bfcfc78 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -1075,19 +1075,25 @@ void exit_itimers(struct signal_struct *sig) } }
-SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, - const struct timespec __user *, tp) +static int __clock_settime(clockid_t which_clock, struct timespec *ts) { struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec new_tp;
if (!kc || !kc->clock_set) return -EINVAL;
+ return kc->clock_set(which_clock, ts); +} + +SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, + const struct timespec __user *, tp) +{ + struct timespec new_tp; + if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
- return kc->clock_set(which_clock, &new_tp); + return __clock_settime(which_clock, &new_tp); }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
This patch introduces the clock_set64 method with timespec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with timespec64 type for the clock_settime syscall function, and change the clock_settime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the clock_set64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 2 ++ kernel/time/posix-timers.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 16c3364..2b19ec8 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -100,6 +100,8 @@ struct k_clock { int (*clock_getres) (const clockid_t which_clock, struct timespec *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_adj) (const clockid_t which_clock, struct timex *tx); int (*timer_create) (struct k_itimer *timer); diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index bfcfc78..3d59efa 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -541,6 +541,18 @@ static int default_timer_set64(struct k_itimer *timr, int flags, return ret; }
+static int default_clock_set64(const clockid_t which_clock, + const struct timespec64 *tp64) +{ + struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec tp; + int ret; + + tp = timespec64_to_timespec(*tp64); + ret = kc->clock_set(which_clock, &tp); + return ret; +} + void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -565,6 +577,8 @@ void posix_timers_register_clock(const clockid_t clock_id, new_clock->timer_get64 = default_timer_get64; if (new_clock->timer_set && !new_clock->timer_set64) new_clock->timer_set64 = default_timer_set64; + if (new_clock->clock_set && !new_clock->clock_set64) + new_clock->clock_set64 = default_clock_set64;
posix_clocks[clock_id] = *new_clock; } @@ -1075,25 +1089,35 @@ void exit_itimers(struct signal_struct *sig) } }
-static int __clock_settime(clockid_t which_clock, struct timespec *ts) +static int __clock_settime(clockid_t which_clock, struct timespec64 *ts) { struct k_clock *kc = clockid_to_kclock(which_clock);
- if (!kc || !kc->clock_set) + if (!kc || !kc->clock_set64) return -EINVAL;
- return kc->clock_set(which_clock, ts); + return kc->clock_set64(which_clock, ts); }
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { +#ifdef CONFIG_64BIT + struct timespec64 new_tp; +#else struct timespec new_tp; + struct timespec64 new_tp64; +#endif
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
+#ifdef CONFIG_64BIT return __clock_settime(which_clock, &new_tp); +#else + new_tp64 = timespec_to_timespec64(new_tp); + return __clock_settime(which_clock, &new_tp64); +#endif }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
On Tue, May 19, 2015 at 5:49 AM, Baolin Wang baolin.wang@linaro.org wrote:
This patch introduces the clock_set64 method with timespec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with timespec64 type for the clock_settime syscall function, and change the clock_settime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the clock_set64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org
include/linux/posix-timers.h | 2 ++ kernel/time/posix-timers.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 16c3364..2b19ec8 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -100,6 +100,8 @@ struct k_clock { int (*clock_getres) (const clockid_t which_clock, struct timespec *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_adj) (const clockid_t which_clock, struct timex *tx); int (*timer_create) (struct k_itimer *timer);
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index bfcfc78..3d59efa 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -541,6 +541,18 @@ static int default_timer_set64(struct k_itimer *timr, int flags, return ret; }
+static int default_clock_set64(const clockid_t which_clock,
const struct timespec64 *tp64)
+{
struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec tp;
int ret;
tp = timespec64_to_timespec(*tp64);
ret = kc->clock_set(which_clock, &tp);
return ret;
+}
void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -565,6 +577,8 @@ void posix_timers_register_clock(const clockid_t clock_id, new_clock->timer_get64 = default_timer_get64; if (new_clock->timer_set && !new_clock->timer_set64) new_clock->timer_set64 = default_timer_set64;
if (new_clock->clock_set && !new_clock->clock_set64)
new_clock->clock_set64 = default_clock_set64; posix_clocks[clock_id] = *new_clock;
} @@ -1075,25 +1089,35 @@ void exit_itimers(struct signal_struct *sig) } }
-static int __clock_settime(clockid_t which_clock, struct timespec *ts) +static int __clock_settime(clockid_t which_clock, struct timespec64 *ts) { struct k_clock *kc = clockid_to_kclock(which_clock);
if (!kc || !kc->clock_set)
if (!kc || !kc->clock_set64) return -EINVAL;
return kc->clock_set(which_clock, ts);
return kc->clock_set64(which_clock, ts);
}
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { +#ifdef CONFIG_64BIT
struct timespec64 new_tp;
+#else struct timespec new_tp;
struct timespec64 new_tp64;
+#endif
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
+#ifdef CONFIG_64BIT return __clock_settime(which_clock, &new_tp); +#else
new_tp64 = timespec_to_timespec64(new_tp);
return __clock_settime(which_clock, &new_tp64);
+#endif }
Please just have two clock_settime functions wrapped by the ifdef conditional. You should always try to avoid ifdefs inside of functions.
thanks -john
On 21 May 2015 at 01:55, John Stultz john.stultz@linaro.org wrote:
On Tue, May 19, 2015 at 5:49 AM, Baolin Wang baolin.wang@linaro.org wrote:
This patch introduces the clock_set64 method with timespec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with timespec64 type for the clock_settime syscall function, and change the clock_settime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the clock_set64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org
include/linux/posix-timers.h | 2 ++ kernel/time/posix-timers.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 16c3364..2b19ec8 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -100,6 +100,8 @@ struct k_clock { int (*clock_getres) (const clockid_t which_clock, struct
timespec *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_adj) (const clockid_t which_clock, struct timex *tx); int (*timer_create) (struct k_itimer *timer);
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index bfcfc78..3d59efa 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -541,6 +541,18 @@ static int default_timer_set64(struct k_itimer
*timr, int flags,
return ret;
}
+static int default_clock_set64(const clockid_t which_clock,
const struct timespec64 *tp64)
+{
struct k_clock *kc = clockid_to_kclock(which_clock);
struct timespec tp;
int ret;
tp = timespec64_to_timespec(*tp64);
ret = kc->clock_set(which_clock, &tp);
return ret;
+}
void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -565,6 +577,8 @@ void posix_timers_register_clock(const clockid_t
clock_id,
new_clock->timer_get64 = default_timer_get64; if (new_clock->timer_set && !new_clock->timer_set64) new_clock->timer_set64 = default_timer_set64;
if (new_clock->clock_set && !new_clock->clock_set64)
new_clock->clock_set64 = default_clock_set64; posix_clocks[clock_id] = *new_clock;
} @@ -1075,25 +1089,35 @@ void exit_itimers(struct signal_struct *sig) } }
-static int __clock_settime(clockid_t which_clock, struct timespec *ts) +static int __clock_settime(clockid_t which_clock, struct timespec64 *ts) { struct k_clock *kc = clockid_to_kclock(which_clock);
if (!kc || !kc->clock_set)
if (!kc || !kc->clock_set64) return -EINVAL;
return kc->clock_set(which_clock, ts);
return kc->clock_set64(which_clock, ts);
}
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { +#ifdef CONFIG_64BIT
struct timespec64 new_tp;
+#else struct timespec new_tp;
struct timespec64 new_tp64;
+#endif
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
+#ifdef CONFIG_64BIT return __clock_settime(which_clock, &new_tp); +#else
new_tp64 = timespec_to_timespec64(new_tp);
return __clock_settime(which_clock, &new_tp64);
+#endif }
Please just have two clock_settime functions wrapped by the ifdef conditional. You should always try to avoid ifdefs inside of functions.
thanks -john
Thanks for your comments. I'll fix that to make it look easily.
On Thursday 21 May 2015 10:24:50 Baolin Wang wrote:
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { +#ifdef CONFIG_64BIT
struct timespec64 new_tp;
+#else struct timespec new_tp;
struct timespec64 new_tp64;
+#endif
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
+#ifdef CONFIG_64BIT return __clock_settime(which_clock, &new_tp); +#else
new_tp64 = timespec_to_timespec64(new_tp);
return __clock_settime(which_clock, &new_tp64);
+#endif }
Please just have two clock_settime functions wrapped by the ifdef conditional. You should always try to avoid ifdefs inside of functions.
Thanks for your comments. I'll fix that to make it look easily.
I think it's best to do it the way I have in my patch series: keep one __clock_settime() function that takes a timespec64 argument, but introduce a get_timespec64() function that copies a __user timespec to a kernel timespec64. By copying the two members individually with get_user(), you can avoid the difference between 32-bit and 64-bit platforms.
Arnd
On 21 May 2015 at 16:13, Arnd Bergmann arnd@linaro.org wrote:
On Thursday 21 May 2015 10:24:50 Baolin Wang wrote:
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, const struct timespec __user *, tp) { +#ifdef CONFIG_64BIT
struct timespec64 new_tp;
+#else struct timespec new_tp;
struct timespec64 new_tp64;
+#endif
if (copy_from_user(&new_tp, tp, sizeof (*tp))) return -EFAULT;
+#ifdef CONFIG_64BIT return __clock_settime(which_clock, &new_tp); +#else
new_tp64 = timespec_to_timespec64(new_tp);
return __clock_settime(which_clock, &new_tp64);
+#endif }
Please just have two clock_settime functions wrapped by the ifdef conditional. You should always try to avoid ifdefs inside of functions.
Thanks for your comments. I'll fix that to make it look easily.
I think it's best to do it the way I have in my patch series: keep one __clock_settime() function that takes a timespec64 argument, but introduce a get_timespec64() function that copies a __user timespec to a kernel timespec64. By copying the two members individually with get_user(), you can avoid the difference between 32-bit and 64-bit platforms.
Arnd
I'll try to modify this patch following the method you suggested in private. Thanks.
This patch splits out the guts of the clock_gettime syscall and changes the clock_gettime syscall implementation to prepare the converting to 64bit methods for the clock_gettime syscall function in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 3d59efa..17bc9af 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -1120,17 +1120,23 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, #endif }
-SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct timespec __user *,tp) +static int __clock_gettime(clockid_t which_clock, struct timespec *ts) { struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec kernel_tp; - int error;
if (!kc) return -EINVAL;
- error = kc->clock_get(which_clock, &kernel_tp); + return kc->clock_get(which_clock, ts); +} + +SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, + struct timespec __user *,tp) +{ + struct timespec kernel_tp; + int error; + + error = __clock_gettime(which_clock, &kernel_tp);
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) error = -EFAULT;
This patch introduces the clock_get64 method with timespec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with timespec64 type for the clock_gettime syscall function, and change the clock_gettime syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the clock_get64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 1 + kernel/time/posix-timers.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 2b19ec8..be2123d 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -103,6 +103,7 @@ struct k_clock { 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, diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 17bc9af..9758eb3 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -553,6 +553,20 @@ static int default_clock_set64(const clockid_t which_clock, return ret; }
+static int default_clock_get64(const clockid_t which_clock, + struct timespec64 *tp64) +{ + struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec tp; + int ret; + + ret = kc->clock_get(which_clock, &tp); + if (!ret) + *tp64 = timespec_to_timespec64(tp); + + return ret; +} + void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -562,8 +576,8 @@ 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; } @@ -579,6 +593,8 @@ void posix_timers_register_clock(const clockid_t clock_id, new_clock->timer_set64 = default_timer_set64; if (new_clock->clock_set && !new_clock->clock_set64) new_clock->clock_set64 = default_clock_set64; + if (new_clock->clock_get && !new_clock->clock_get64) + new_clock->clock_get64 = default_clock_get64;
posix_clocks[clock_id] = *new_clock; } @@ -1120,23 +1136,32 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, #endif }
-static int __clock_gettime(clockid_t which_clock, struct timespec *ts) +static int __clock_gettime(clockid_t which_clock, struct timespec64 *ts) { struct k_clock *kc = clockid_to_kclock(which_clock);
if (!kc) return -EINVAL;
- return kc->clock_get(which_clock, ts); + return kc->clock_get64(which_clock, ts); }
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, struct timespec __user *,tp) { - struct timespec kernel_tp; int error; +#ifdef CONFIG_64BIT + struct timespec64 kernel_tp;
error = __clock_gettime(which_clock, &kernel_tp); +#else + struct timespec64 kernel_tp64; + struct timespec kernel_tp; + + error = __clock_gettime(which_clock, &kernel_tp64); + if (!error) + kernel_tp = timespec64_to_timespec(kernel_tp64); +#endif
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) error = -EFAULT;
This patch splits out the guts of the clock_getres syscall and changes the clock_getres syscall implementation to prepare the converting to 64bit methods for the clock_getres syscall function in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 9758eb3..d6aeb13 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -1192,17 +1192,23 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, return err; }
-SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, - struct timespec __user *, tp) +static int __clock_getres(clockid_t which_clock, struct timespec *ts) { struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec rtn_tp; - int error;
if (!kc) return -EINVAL;
- error = kc->clock_getres(which_clock, &rtn_tp); + return kc->clock_getres(which_clock, ts); +} + +SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, + struct timespec __user *, tp) +{ + struct timespec rtn_tp; + int error; + + error = __clock_getres(which_clock, &rtn_tp);
if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) error = -EFAULT;
This patch introduces the clock_getres64 method with timespec64 type for k_clock structure, that makes it ready for the 2038 year.
Convert to the 64bit method with timespec64 type for the clock_getres syscall function, and change the clock_getres syscall implementation according to the CONFIG_64BIT macro.
Also add a default 64bit method for the clock_getres64 pointer of k_clock structure, and it will be removed after all the drivers are converted to 64bit methods.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 1 + kernel/time/posix-timers.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index be2123d..35786c5 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -98,6 +98,7 @@ 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, diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index d6aeb13..dd04d68 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -567,6 +567,20 @@ static int default_clock_get64(const clockid_t which_clock, return ret; }
+static int default_clock_getres64(const clockid_t which_clock, + struct timespec64 *tp64) +{ + struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec tp; + int ret; + + ret = kc->clock_getres(which_clock, &tp); + if (!ret) + *tp64 = timespec_to_timespec64(tp); + + return 0; +} + void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -581,8 +595,8 @@ void posix_timers_register_clock(const clockid_t clock_id, 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; } @@ -595,6 +609,8 @@ void posix_timers_register_clock(const clockid_t clock_id, new_clock->clock_set64 = default_clock_set64; if (new_clock->clock_get && !new_clock->clock_get64) new_clock->clock_get64 = default_clock_get64; + if (new_clock->clock_getres && !new_clock->clock_getres64) + new_clock->clock_getres64 = default_clock_getres64;
posix_clocks[clock_id] = *new_clock; } @@ -642,7 +658,8 @@ 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]; } @@ -1192,23 +1209,32 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, return err; }
-static int __clock_getres(clockid_t which_clock, struct timespec *ts) +static int __clock_getres(clockid_t which_clock, struct timespec64 *ts) { struct k_clock *kc = clockid_to_kclock(which_clock);
if (!kc) return -EINVAL;
- return kc->clock_getres(which_clock, ts); + return kc->clock_getres64(which_clock, ts); }
SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp) { - struct timespec rtn_tp; int error; +#ifdef CONFIG_64BIT + struct timespec64 rtn_tp;
error = __clock_getres(which_clock, &rtn_tp); +#else + struct timespec64 rtn_tp64; + struct timespec rtn_tp; + + error = __clock_getres(which_clock, &rtn_tp64); + if (!error) + rtn_tp = timespec64_to_timespec(rtn_tp64); +#endif
if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) error = -EFAULT;
This patch converts the timespec type to timespec64 type for timekeeping_clocktai() function which is used only in the posix-timers.c file, that makes it ready for 2038 issue.
And remove the declaration of timekeeping_clocktai() in kernel/time/timekeeping.h file, cause nothing uses that declaration now, and it would conflict with the inline definition in the include/linux/timekeeping.h file.
Also introduce the clock_get64 callback pointer for the k_clock structure, and convert the timespec type to timespec64 type for the posix_get_tai() function.
Next patch will convert all the timespec/itimerspec to the timespec64/itimerspec64 type for other callbacks of the k_clock structure in the kernel/time/posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/timekeeping.h | 4 ++-- kernel/time/posix-timers.c | 4 ++-- kernel/time/timekeeping.h | 1 - 3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 89beb62..c3345d5 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -250,9 +250,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 dd04d68..daa3553 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -267,7 +267,7 @@ static int posix_get_boottime(const clockid_t which_clock, struct timespec *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; @@ -314,7 +314,7 @@ static __init int init_posix_timers(void) }; struct k_clock clock_tai = { .clock_getres = hrtimer_get_res, - .clock_get = posix_get_tai, + .clock_get64 = posix_get_tai, .nsleep = common_nsleep, .nsleep_restart = hrtimer_nanosleep_restart, .timer_create = common_timer_create, diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h index 1d91416..04c7943 100644 --- a/kernel/time/timekeeping.h +++ b/kernel/time/timekeeping.h @@ -15,7 +15,6 @@ 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 int timekeeping_suspend(void); extern void timekeeping_resume(void);
This patch converts the timespec type to timespec64 type and converts the itimerspec type to itimerspec64 type for k_clock callback functions in posix-timers.c file.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- kernel/time/posix-timers.c | 92 ++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index daa3553..fe3ca19 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); @@ -204,17 +204,17 @@ 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); + return do_sys_settimeofday64(tp, NULL); }
static int posix_clock_realtime_adj(const clockid_t which_clock, @@ -226,44 +226,44 @@ 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; }
@@ -279,57 +279,57 @@ static int posix_get_tai(clockid_t which_clock, struct timespec64 *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_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, };
@@ -806,7 +806,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; @@ -817,7 +817,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; @@ -843,7 +843,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); }
static int __timer_gettime(timer_t timer_id, struct itimerspec64 *cur_setting) @@ -918,7 +918,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; @@ -947,10 +947,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)) {
This patch converts the timespec/itimerspec type to timespec64/itimerspec64 type for k_clock callback functions in mmtimer.c file, that makes it ready for 2038 issue.
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 64bit methods with timespec64/itimerspec64 type of k_clock structure in alarmtimer.c file, that makes it ready for 2038 issue.
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, };
To make it is ready for 2038 issue when implementing the conversion between cputime and timespec64, this patch introduces the timespec64_to_jiffies() and jiffies_to_timespec64() functions.
And move the old functions timespec64_to_jiffies() and jiffies_to_timespec64() to jiffies.h file, for it is convenient to delete them later.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/jiffies.h | 21 ++++++++++++++++++--- kernel/time/time.c | 12 ++++++------ 2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c367cbd..16a30c1 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -290,9 +290,24 @@ static inline u64 jiffies_to_nsecs(const unsigned long j)
extern unsigned long msecs_to_jiffies(const unsigned int m); 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 __timespec_to_jiffies(unsigned long sec, long nsec); +extern unsigned long timespec64_to_jiffies(const struct timespec64 *value); +extern void jiffies_to_timespec64(const unsigned long jiffies, + struct timespec64 *value); +static inline unsigned long timespec_to_jiffies(const struct timespec *value) +{ + return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); +} + +static inline void jiffies_to_timespec(const unsigned long jiffies, + struct timespec *value) +{ + struct timespec64 *ts; + + *ts = timespec_to_timespec64(*value); + jiffies_to_timespec64(jiffies, ts); +} + 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 33c539b..2ffb5e7 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -569,7 +569,7 @@ EXPORT_SYMBOL(usecs_to_jiffies); * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec * value to a scaled second value. */ -static unsigned long +unsigned long __timespec_to_jiffies(unsigned long sec, long nsec) { nsec = nsec + TICK_NSEC - 1; @@ -583,17 +583,17 @@ __timespec_to_jiffies(unsigned long sec, long nsec) (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
} +EXPORT_SYMBOL(__timespec_to_jiffies);
unsigned long -timespec_to_jiffies(const struct timespec *value) +timespec64_to_jiffies(const struct timespec64 *value) { return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); } - -EXPORT_SYMBOL(timespec_to_jiffies); +EXPORT_SYMBOL(timespec64_to_jiffies);
void -jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) +jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value) { /* * Convert jiffies to nanoseconds and separate with @@ -604,7 +604,7 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) NSEC_PER_SEC, &rem); value->tv_nsec = rem; } -EXPORT_SYMBOL(jiffies_to_timespec); +EXPORT_SYMBOL(jiffies_to_timespec64);
/* * We could use a similar algorithm to timespec_to_jiffies (with a
On Tuesday 19 May 2015 20:50:02 Baolin Wang wrote:
+static inline void jiffies_to_timespec(const unsigned long jiffies,
struct timespec *value)
+{
struct timespec64 *ts;
*ts = timespec_to_timespec64(*value);
jiffies_to_timespec64(jiffies, ts);
+}
You are dereferencing an uninitialized pointer here. Did you compile-test this? You should have seen a warning from gcc.
Arnd
On 20 May 2015 at 20:34, Arnd Bergmann arnd@linaro.org wrote:
On Tuesday 19 May 2015 20:50:02 Baolin Wang wrote:
+static inline void jiffies_to_timespec(const unsigned long jiffies,
struct timespec *value)
+{
struct timespec64 *ts;
*ts = timespec_to_timespec64(*value);
jiffies_to_timespec64(jiffies, ts);
+}
You are dereferencing an uninitialized pointer here. Did you compile-test this? You should have seen a warning from gcc.
Arnd
Sorry to miss that, I'll fix that asap, thanks.
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. The cputime_to_timespec/timespec_to_cputime functions are moved to include/linux/cputime.h file for removing conveniently.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- arch/powerpc/include/asm/cputime.h | 6 +++--- arch/s390/include/asm/cputime.h | 8 ++++---- include/asm-generic/cputime_jiffies.h | 10 +++++----- include/asm-generic/cputime_nsecs.h | 4 ++-- include/linux/cputime.h | 15 +++++++++++++++ 5 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index e245255..5dda5c0 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h @@ -154,9 +154,9 @@ static inline cputime_t secs_to_cputime(const unsigned long sec) }
/* - * Convert cputime <-> timespec + * Convert cputime <-> timespec64 */ -static inline void cputime_to_timespec(const cputime_t ct, struct timespec *p) +static inline void cputime_to_timespec64(const cputime_t ct, struct timespec64 *p) { u64 x = (__force u64) ct; unsigned int frac; @@ -168,7 +168,7 @@ static inline void cputime_to_timespec(const cputime_t ct, struct timespec *p) p->tv_nsec = x; }
-static inline cputime_t timespec_to_cputime(const struct timespec *p) +static inline cputime_t timespec64_to_cputime(const struct timespec64 *p) { u64 ct;
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index b91e960..1266697 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -89,16 +89,16 @@ static inline cputime_t secs_to_cputime(const unsigned int s) }
/* - * Convert cputime to timespec and back. + * Convert cputime to timespec64 and back. */ -static inline cputime_t timespec_to_cputime(const struct timespec *value) +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_timespec(const cputime_t cputime, - struct timespec *value) +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 diff --git a/include/asm-generic/cputime_jiffies.h b/include/asm-generic/cputime_jiffies.h index fe386fc..54e034c 100644 --- a/include/asm-generic/cputime_jiffies.h +++ b/include/asm-generic/cputime_jiffies.h @@ -44,12 +44,12 @@ typedef u64 __nocast cputime64_t; #define secs_to_cputime(sec) jiffies_to_cputime((sec) * HZ)
/* - * Convert cputime to timespec and back. + * Convert cputime to timespec64 and back. */ -#define timespec_to_cputime(__val) \ - jiffies_to_cputime(timespec_to_jiffies(__val)) -#define cputime_to_timespec(__ct,__val) \ - jiffies_to_timespec(cputime_to_jiffies(__ct),__val) +#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. diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h index 0419485..65c875b 100644 --- a/include/asm-generic/cputime_nsecs.h +++ b/include/asm-generic/cputime_nsecs.h @@ -73,12 +73,12 @@ typedef u64 __nocast cputime64_t; /* * Convert cputime <-> timespec (nsec) */ -static inline cputime_t timespec_to_cputime(const struct timespec *val) +static inline cputime_t timespec64_to_cputime(const struct timespec64 *val) { u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec; return (__force cputime_t) ret; } -static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) +static inline void cputime_to_timespec64(const cputime_t ct, struct timespec64 *val) { u32 rem;
diff --git a/include/linux/cputime.h b/include/linux/cputime.h index f2eb2ee..f01896f 100644 --- a/include/linux/cputime.h +++ b/include/linux/cputime.h @@ -13,4 +13,19 @@ usecs_to_cputime((__nsecs) / NSEC_PER_USEC) #endif
+static inline cputime_t timespec_to_cputime(const struct timespec *ts) +{ + struct timespec64 ts64 = timespec_to_timespec64(*ts); + return timespec64_to_cputime(&ts64); +} + +static inline void cputime_to_timespec(const cputime_t cputime, + struct timespec *value) +{ + struct timespec64 *ts64; + + *ts64 = timespec_to_timespec64(*value); + cputime_to_timespec64(cputime, ts64); +} + #endif /* __LINUX_CPUTIME_H */
On Tuesday 19 May 2015 20:50:03 Baolin Wang wrote:
+static inline void cputime_to_timespec(const cputime_t cputime,
struct timespec *value)
+{
struct timespec64 *ts64;
*ts64 = timespec_to_timespec64(*value);
cputime_to_timespec64(cputime, ts64);
Another mistake as before: derferencing an uninitialized pointer.
Arnd
On 20 May 2015 at 20:35, Arnd Bergmann arnd@linaro.org wrote:
On Tuesday 19 May 2015 20:50:03 Baolin Wang wrote:
+static inline void cputime_to_timespec(const cputime_t cputime,
struct timespec *value)
+{
struct timespec64 *ts64;
*ts64 = timespec_to_timespec64(*value);
cputime_to_timespec64(cputime, ts64);
Another mistake as before: derferencing an uninitialized pointer.
Arnd
I'll fix that in next patch, thanks.
This patch changes to the new 64bit methods with timespec64/itimerspec64 type for the k_clock structure in posix-cpu-timers.c file, that makes it ready for 2038 issue.
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..a4651cd 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);
On Tuesday 19 May 2015 20:50:04 Baolin Wang wrote:
@@ -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;
And one more bug of this kind here.
Arnd
On 20 May 2015 at 20:40, Arnd Bergmann arnd@linaro.org wrote:
On Tuesday 19 May 2015 20:50:04 Baolin Wang wrote:
@@ -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;
And one more bug of this kind here.
Arnd
Another dereferencing an uninitialized pointer? I'll fix that in next patch. Thanks.
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 year.
Signed-off-by: Baolin Wang baolin.wang@linaro.org --- include/linux/posix-timers.h | 9 ----- kernel/time/posix-timers.c | 90 +++--------------------------------------- 2 files changed, 5 insertions(+), 94 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 fe3ca19..53347f4 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -140,7 +140,6 @@ static int common_timer_del(struct k_itimer *timer); static enum hrtimer_restart posix_timer_fn(struct hrtimer *data);
static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags); -static struct k_clock *clockid_to_kclock(const clockid_t id);
#define lock_timer(tid, flags) \ ({ struct k_itimer *__timr; \ @@ -514,73 +513,6 @@ static struct pid *good_sigevent(sigevent_t * event) return task_pid(rtn); }
-static void default_timer_get64(struct k_itimer *timr, - struct itimerspec64 *cur_setting64) -{ - struct itimerspec cur_setting; - struct k_clock *kc = clockid_to_kclock(timr->it_clock); - - kc->timer_get(timr, &cur_setting); - *cur_setting64 = itimerspec_to_itimerspec64(&cur_setting); -} - -static int default_timer_set64(struct k_itimer *timr, int flags, - struct itimerspec64 *new_setting64, - struct itimerspec64 *old_setting64) -{ - struct k_clock *kc = clockid_to_kclock(timr->it_clock); - struct itimerspec new_setting, old_setting; - struct itimerspec *rtn = old_setting64 ? &old_setting : NULL; - int ret; - - new_setting = itimerspec64_to_itimerspec(new_setting64); - ret = kc->timer_set(timr, flags, &new_setting, rtn); - if (!ret && old_setting64) - *old_setting64 = itimerspec_to_itimerspec64(&old_setting); - - return ret; -} - -static int default_clock_set64(const clockid_t which_clock, - const struct timespec64 *tp64) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec tp; - int ret; - - tp = timespec64_to_timespec(*tp64); - ret = kc->clock_set(which_clock, &tp); - return ret; -} - -static int default_clock_get64(const clockid_t which_clock, - struct timespec64 *tp64) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec tp; - int ret; - - ret = kc->clock_get(which_clock, &tp); - if (!ret) - *tp64 = timespec_to_timespec64(tp); - - return ret; -} - -static int default_clock_getres64(const clockid_t which_clock, - struct timespec64 *tp64) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec tp; - int ret; - - ret = kc->clock_getres(which_clock, &tp); - if (!ret) - *tp64 = timespec_to_timespec64(tp); - - return 0; -} - void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock) { @@ -590,28 +522,17 @@ 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; }
- if (new_clock->timer_get && !new_clock->timer_get64) - new_clock->timer_get64 = default_timer_get64; - if (new_clock->timer_set && !new_clock->timer_set64) - new_clock->timer_set64 = default_timer_set64; - if (new_clock->clock_set && !new_clock->clock_set64) - new_clock->clock_set64 = default_clock_set64; - if (new_clock->clock_get && !new_clock->clock_get64) - new_clock->clock_get64 = default_clock_get64; - if (new_clock->clock_getres && !new_clock->clock_getres64) - new_clock->clock_getres64 = default_clock_getres64; - posix_clocks[clock_id] = *new_clock; } EXPORT_SYMBOL_GPL(posix_timers_register_clock); @@ -658,8 +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 - && !posix_clocks[id].clock_getres64)) + if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres64) return NULL; return &posix_clocks[id]; }