This patch does a lot of things at once, and needs to be split up into several small steps:
- split out base function from non-compat syscalls - convert all nanosleep syscall restart handling to use __kernel_timespec - make compat syscalls use the common base functions - change normal syscalls to use __kernel_timespec
Most syscalls here are done in a simple way, the main complications is from cleaning up the compat handling to not take an extra step of get_fs()/set_fs(), which we would not actually have to do.
The nanosleep handling is still very ugly, maybe we can come up with a better implementation for that in the process as well.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- include/linux/hrtimer.h | 2 +- include/linux/posix-timers.h | 2 +- include/linux/syscalls.h | 19 +-- include/linux/thread_info.h | 6 +- ipc/syscall.c | 2 +- kernel/compat.c | 15 ++- kernel/time/alarmtimer.c | 13 +- kernel/time/hrtimer.c | 20 ++-- kernel/time/posix-cpu-timers.c | 14 ++- kernel/time/posix-timers.c | 263 +++++++++++++++++++++++------------------ 10 files changed, 203 insertions(+), 153 deletions(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 05f6df1fdf5b..204eaa8843dd 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -427,7 +427,7 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,
/* Precise sleep: */ extern long hrtimer_nanosleep(struct timespec *rqtp, - struct timespec __user *rmtp, + struct __kernel_timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid); extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 28637f929458..17caa82c2ed1 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -104,7 +104,7 @@ struct k_clock { int (*clock_adj) (const clockid_t which_clock, struct __kernel_timex *tx); int (*timer_create) (struct k_itimer *timer); int (*nsleep) (const clockid_t which_clock, int flags, - struct timespec *, struct timespec __user *); + struct timespec *, struct __kernel_timespec __user *); long (*nsleep_restart) (struct restart_block *restart_block); int (*timer_set) (struct k_itimer * timr, int flags, struct itimerspec * new_setting, diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index eb58a31979fc..be9a909b1176 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -216,7 +216,8 @@ asmlinkage long sys_adjtimex(struct __kernel_timex __user *txc_p); asmlinkage long sys_times(struct tms __user *tbuf);
asmlinkage long sys_gettid(void); -asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp); +asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, + struct __kernel_timespec __user *rmtp); asmlinkage long sys_alarm(unsigned int seconds); asmlinkage long sys_getpid(void); asmlinkage long sys_getppid(void); @@ -264,23 +265,23 @@ asmlinkage long sys_timer_create(clockid_t which_clock, struct sigevent __user *timer_event_spec, timer_t __user * created_timer_id); asmlinkage long sys_timer_gettime(timer_t timer_id, - struct itimerspec __user *setting); + struct __kernel_itimerspec __user *setting); asmlinkage long sys_timer_getoverrun(timer_t timer_id); asmlinkage long sys_timer_settime(timer_t timer_id, int flags, - const struct itimerspec __user *new_setting, - struct itimerspec __user *old_setting); + const struct __kernel_itimerspec __user *new_setting, + struct __kernel_itimerspec __user *old_setting); asmlinkage long sys_timer_delete(timer_t timer_id); asmlinkage long sys_clock_settime(clockid_t which_clock, - const struct timespec __user *tp); + const struct __kernel_timespec __user *tp); asmlinkage long sys_clock_gettime(clockid_t which_clock, - struct timespec __user *tp); + struct __kernel_timespec __user *tp); asmlinkage long sys_clock_adjtime(clockid_t which_clock, struct __kernel_timex __user *tx); asmlinkage long sys_clock_getres(clockid_t which_clock, - struct timespec __user *tp); + struct __kernel_timespec __user *tp); asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags, - const struct timespec __user *rqtp, - struct timespec __user *rmtp); + const struct __kernel_timespec __user *rqtp, + struct __kernel_timespec __user *rmtp);
asmlinkage long sys_nice(int increment); asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 43686bb94374..6039931ac513 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -10,7 +10,7 @@ #include <linux/types.h> #include <linux/bug.h>
-struct timespec; +struct __kernel_timespec; struct compat_timespec;
/* @@ -31,9 +31,11 @@ struct restart_block { /* For nanosleep */ struct { clockid_t clockid; - struct timespec __user *rmtp; #ifdef CONFIG_COMPAT_TIME + struct __kernel_timespec __user *rmtp; struct compat_timespec __user *compat_rmtp; +#else + struct timespec __user *rmtp; #endif u64 expires; } nanosleep; diff --git a/ipc/syscall.c b/ipc/syscall.c index d7b17355d870..106d35e4f719 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -34,7 +34,7 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, #else return sys_semtimedop(first, (struct sembuf __user *)ptr, second, - (const struct timespec __user *)fifth); + (const struct __kernel_timespec __user *)fifth); #endif
case SEMGET: diff --git a/kernel/compat.c b/kernel/compat.c index 1837c8ec79cf..7a29df113058 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -253,11 +253,11 @@ int compat_convert_timespec(struct timespec __user **kts, static long compat_nanosleep_restart(struct restart_block *restart) { struct compat_timespec __user *rmtp; - struct timespec rmt; + struct __kernel_timespec rmt; mm_segment_t oldfs; long ret;
- restart->nanosleep.rmtp = (struct timespec __user *) &rmt; + restart->nanosleep.rmtp = (struct __kernel_timespec __user *) &rmt; oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep_restart(restart); @@ -266,7 +266,8 @@ static long compat_nanosleep_restart(struct restart_block *restart) if (ret == -ERESTART_RESTARTBLOCK) { rmtp = restart->nanosleep.compat_rmtp;
- if (rmtp && compat_put_timespec(&rmt, rmtp)) + if (rmtp && put_user(rmt.tv_sec, &rmtp->tv_sec) && + put_user(rmt.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; }
@@ -276,7 +277,8 @@ static long compat_nanosleep_restart(struct restart_block *restart) COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { - struct timespec tu, rmt; + struct timespec tu; + struct __kernel_timespec rmt; mm_segment_t oldfs; long ret;
@@ -289,7 +291,7 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep(&tu, - rmtp ? (struct timespec __user *)&rmt : NULL, + rmtp ? (struct __kernel_timespec __user *)&rmt : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC); set_fs(oldfs);
@@ -318,7 +320,8 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, restart->fn = compat_nanosleep_restart; restart->nanosleep.compat_rmtp = rmtp;
- if (rmtp && compat_put_timespec(&rmt, rmtp)) + if (rmtp && put_user(rmt.tv_sec, &rmtp->tv_sec) && + put_user(rmt.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 1b001ed1edb9..d980d45603d5 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -679,18 +679,18 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) * now and the exp value */ static int update_rmtp(ktime_t exp, enum alarmtimer_type type, - struct timespec __user *rmtp) + struct __kernel_timespec __user *rmtp) { - struct timespec rmt; + struct timespec64 rmt; ktime_t rem;
rem = ktime_sub(exp, alarm_bases[type].gettime());
if (rem.tv64 <= 0) return 0; - rmt = ktime_to_timespec(rem); + rmt = ktime_to_timespec64(rem);
- if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) + if (put_timespec64(&rmt, rmtp)); return -EFAULT;
return 1; @@ -707,7 +707,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) { enum alarmtimer_type type = restart->nanosleep.clockid; ktime_t exp; - struct timespec __user *rmtp; + struct __kernel_timespec __user *rmtp; struct alarm alarm; int ret = 0;
@@ -744,7 +744,8 @@ out: * Handles clock_nanosleep calls against _ALARM clockids */ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, - struct timespec *tsreq, struct timespec __user *rmtp) + struct timespec *tsreq, + struct __kernel_timespec __user *rmtp) { enum alarmtimer_type type = clock2alarm(which_clock); struct alarm alarm; diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 76d4bd962b19..9ffd943a0d1d 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1511,17 +1511,17 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod return t->task == NULL; }
-static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) +static int update_rmtp(struct hrtimer *timer, struct __kernel_timespec __user *rmtp) { - struct timespec rmt; + struct timespec64 rmt; ktime_t rem;
rem = hrtimer_expires_remaining(timer); if (rem.tv64 <= 0) return 0; - rmt = ktime_to_timespec(rem); + rmt = ktime_to_timespec64(rem);
- if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) + if (put_timespec64(&rmt, rmtp)) return -EFAULT;
return 1; @@ -1530,7 +1530,7 @@ static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) long __sched hrtimer_nanosleep_restart(struct restart_block *restart) { struct hrtimer_sleeper t; - struct timespec __user *rmtp; + struct __kernel_timespec __user *rmtp; int ret = 0;
hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, @@ -1554,7 +1554,7 @@ out: return ret; }
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, +long hrtimer_nanosleep(struct timespec *rqtp, struct __kernel_timespec __user *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; @@ -1595,13 +1595,15 @@ out: return ret; }
-SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp, + struct __kernel_timespec __user *, rmtp) { struct timespec tu; + struct timespec64 tu64;
- if (copy_from_user(&tu, rqtp, sizeof(tu))) + if (get_timespec64(&tu64, rqtp)) return -EFAULT; + tu = timespec64_to_timespec(tu64);
if (!timespec_valid(&tu)) return -EINVAL; diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 0075da74abf0..0f21086055fe 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -1332,7 +1332,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, static long posix_cpu_nsleep_restart(struct restart_block *restart_block);
static int posix_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec *rqtp, struct timespec __user *rmtp) + struct timespec *rqtp, + struct __kernel_timespec __user *rmtp) { struct restart_block *restart_block = ¤t->restart_block; struct itimerspec it; @@ -1349,13 +1350,13 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
if (error == -ERESTART_RESTARTBLOCK) { - + struct timespec64 it_value = timespec_to_timespec64(it.it_value); if (flags & TIMER_ABSTIME) return -ERESTARTNOHAND; /* * Report back to the user the time still remaining. */ - if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) + if (rmtp && put_timespec64(&it_value, rmtp)) return -EFAULT;
restart_block->fn = posix_cpu_nsleep_restart; @@ -1378,11 +1379,12 @@ static long posix_cpu_nsleep_restart(struct restart_block *restart_block) error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
if (error == -ERESTART_RESTARTBLOCK) { - struct timespec __user *rmtp = restart_block->nanosleep.rmtp; + struct __kernel_timespec __user *rmtp = restart_block->nanosleep.rmtp; + struct timespec64 it_value = timespec_to_timespec64(it.it_value); /* * Report back to the user the time still remaining. */ - if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) + if (rmtp && put_timespec64(&it_value, rmtp)) return -EFAULT;
restart_block->nanosleep.expires = timespec_to_ns(&t); @@ -1411,7 +1413,7 @@ static int process_cpu_timer_create(struct k_itimer *timer) } static int process_cpu_nsleep(const clockid_t which_clock, int flags, struct timespec *rqtp, - struct timespec __user *rmtp) + struct __kernel_timespec __user *rmtp) { return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); } diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 0b4ae6ad825a..fb8b777e5c4f 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -30,6 +30,8 @@ /* These are all the functions necessary to implement * POSIX clocks & timers */ +#include <linux/compat.h> +#include <linux/compat_time.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -39,7 +41,6 @@ #include <asm/uaccess.h> #include <linux/list.h> #include <linux/init.h> -#include <linux/compat.h> #include <linux/compiler.h> #include <linux/hash.h> #include <linux/posix-clock.h> @@ -131,7 +132,7 @@ static struct k_clock posix_clocks[MAX_CLOCKS]; * These ones are defined below. */ static int common_nsleep(const clockid_t, int flags, struct timespec *t, - struct timespec __user *rmtp); + struct __kernel_timespec __user *rmtp); static int common_timer_create(struct k_itimer *new_timer); static void common_timer_get(struct k_itimer *, struct itimerspec *); static int common_timer_set(struct k_itimer *, int, @@ -767,11 +768,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 *setting) { - struct itimerspec cur_setting; struct k_itimer *timr; struct k_clock *kc; unsigned long flags; @@ -785,11 +783,22 @@ 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, setting);
unlock_timer(timr, flags);
- if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) + return ret; +} + +/* Get the time remaining on a POSIX.1b interval timer. */ +SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, + struct __kernel_itimerspec __user *, setting) +{ + struct itimerspec cur_setting; + int ret; + + ret = timer_gettime(timer_id, &cur_setting); + if (!ret && put_itimerspec(&cur_setting, setting)) return -EFAULT;
return ret; @@ -905,28 +914,17 @@ 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 __user *old_spec) { struct k_itimer *timr; - struct itimerspec new_spec, old_spec; - int error = 0; + int error; 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)) + if (!timespec_valid(&new_spec->it_interval) || + !timespec_valid(&new_spec->it_value)) return -EINVAL; -retry: timr = lock_timer(timer_id, &flag); if (!timr) return -EINVAL; @@ -935,16 +933,35 @@ 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); + + return error; +} + +/* Set a POSIX.1b interval timer */ +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, + const struct __kernel_itimerspec __user *, new_setting, + struct __kernel_itimerspec __user *, old_setting) +{ + struct itimerspec new_spec, old_spec; + int error; + struct itimerspec *rtn = old_setting ? &old_spec : NULL; + + if (!new_setting) + return -EINVAL; + + if (get_itimerspec(&new_spec, new_setting)) + return -EFAULT; +retry: + error = timer_settime(timer_id, flags, &new_spec, rtn); if (error == TIMER_RETRY) { rtn = NULL; // We already got the old time... goto retry; }
- if (old_setting && !error && - copy_to_user(old_setting, &old_spec, sizeof (old_spec))) + if (old_setting && !error && put_itimerspec(&old_spec, old_setting)); error = -EFAULT;
return error; @@ -1037,8 +1054,7 @@ 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 timespec64 *tp) { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec new_tp; @@ -1046,14 +1062,23 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, if (!kc || !kc->clock_set) return -EINVAL;
- if (copy_from_user(&new_tp, tp, sizeof (*tp))) - return -EFAULT; + new_tp = timespec64_to_timespec(*tp);
return kc->clock_set(which_clock, &new_tp); }
-SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct timespec __user *,tp) +SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, + const struct __kernel_timespec __user *, tp) +{ + struct timespec64 new_tp64; + + if (get_timespec64(&new_tp64, tp)) + return -EFAULT; + + return clock_settime(which_clock, &new_tp64); +} + +static int clock_gettime(clockid_t which_clock, struct timespec64 *tp) { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec kernel_tp; @@ -1064,7 +1089,20 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
error = kc->clock_get(which_clock, &kernel_tp);
- if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) + *tp = timespec_to_timespec64(kernel_tp); + + return error; +} + +SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, + struct __kernel_timespec __user *,tp) +{ + struct timespec64 kernel_tp64; + int error; + + error = clock_gettime(which_clock, &kernel_tp64); + + if (!error && put_timespec64(&kernel_tp64, tp)) error = -EFAULT;
return error; @@ -1099,8 +1137,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, return err; }
-SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, - struct timespec __user *, tp) +int clock_getres(const clockid_t which_clock, struct timespec64 __user * tp) { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec rtn_tp; @@ -1111,7 +1148,21 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
error = kc->clock_getres(which_clock, &rtn_tp);
- if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) + *tp = timespec_to_timespec64(rtn_tp); + + return error; + +} + +SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, + struct __kernel_timespec __user *, tp) +{ + struct timespec64 rtn_tp64; + int error; + + error = clock_getres(which_clock, &rtn_tp64); + + if (!error && put_timespec64(&rtn_tp64, tp)) error = -EFAULT;
return error; @@ -1121,16 +1172,16 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, * nanosleep for monotonic and realtime clocks */ static int common_nsleep(const clockid_t which_clock, int flags, - struct timespec *tsave, struct timespec __user *rmtp) + struct timespec *tsave, + struct __kernel_timespec __user *rmtp) { return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); }
-SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, - const struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +static int clock_nanosleep(clockid_t which_clock, int flags, struct timespec64 *rqtp, + struct __kernel_timespec __user * rmtp) { struct k_clock *kc = clockid_to_kclock(which_clock); struct timespec t; @@ -1140,8 +1191,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, if (!kc->nsleep) return -ENANOSLEEP_NOTSUP;
- if (copy_from_user(&t, rqtp, sizeof (struct timespec))) - return -EFAULT; + t = timespec64_to_timespec(*rqtp);
if (!timespec_valid(&t)) return -EINVAL; @@ -1149,92 +1199,78 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, return kc->nsleep(which_clock, flags, &t, rmtp); }
-/* - * This will restart clock_nanosleep. This is required only by - * compat_clock_nanosleep_restart for now. - */ -static long clock_nanosleep_restart(struct restart_block *restart_block) +SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, + const struct __kernel_timespec __user *, rqtp, + struct __kernel_timespec __user *, rmtp) { - clockid_t which_clock = restart_block->nanosleep.clockid; - struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 t64;
- if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) - return -EINVAL; + if (get_timespec64(&t64, rqtp)) + return -EFAULT;
- return kc->nsleep_restart(restart_block); + return clock_nanosleep(which_clock, flags, &t64, rmtp); }
#ifdef CONFIG_COMPAT_TIME COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - struct compat_itimerspec __user *, new, - struct compat_itimerspec __user *, old) + struct compat_itimerspec __user *, new_setting, + struct compat_itimerspec __user *, old_setting) { - long err; - mm_segment_t oldfs; - struct itimerspec newts, oldts; + long error; + struct itimerspec new_spec, old_spec; + struct itimerspec *rtn = old_setting ? &old_spec : NULL;
- if (!new) + if (!new_setting) return -EINVAL; - if (get_compat_itimerspec(&newts, new)) + + if (get_compat_itimerspec(&new_spec, new_setting)) return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_timer_settime(timer_id, flags, - (struct itimerspec __user *) &newts, - (struct itimerspec __user *) &oldts); - set_fs(oldfs); - if (!err && old && put_compat_itimerspec(old, &oldts)) +retry: + error = timer_settime(timer_id, flags, &new_spec, rtn); + if (error == TIMER_RETRY) { + rtn = NULL; // We already got the old time... + goto retry; + } + + error = timer_settime(timer_id, flags, &new_spec, &old_spec); + if (!error && old_setting && put_compat_itimerspec(old_setting, &old_spec)) return -EFAULT; - return err; + + return error; }
COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, struct compat_itimerspec __user *, setting) { long err; - mm_segment_t oldfs; struct itimerspec ts;
- oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_timer_gettime(timer_id, - (struct itimerspec __user *) &ts); - set_fs(oldfs); + err = timer_gettime(timer_id, &ts); + if (!err && put_compat_itimerspec(setting, &ts)) return -EFAULT; + return err; }
COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, struct compat_timespec __user *, tp) { - long err; - mm_segment_t oldfs; - struct timespec ts; + struct timespec64 ts;
- if (compat_get_timespec(&ts, tp)) + if (compat_get_timespec64(&ts, tp)) return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_settime(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - return err; + return clock_settime(which_clock, &ts); }
COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, struct compat_timespec __user *, tp) { long err; - mm_segment_t oldfs; - struct timespec ts; + struct timespec64 ts;
- oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_gettime(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - if (!err && compat_put_timespec(&ts, tp)) + err = clock_gettime(which_clock, &ts); + if (!err && compat_put_timespec64(&ts, tp)) return -EFAULT; return err; } @@ -1261,35 +1297,37 @@ COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, struct compat_timespec __user *, tp) { - long err; - mm_segment_t oldfs; - struct timespec ts; + int err; + struct timespec64 ts;
- oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_getres(which_clock, - (struct timespec __user *) &ts); - set_fs(oldfs); - if (!err && tp && compat_put_timespec(&ts, tp)) + err = clock_getres(which_clock, &ts); + if (!err && tp && compat_put_timespec64(&ts, tp)) return -EFAULT; return err; }
static long compat_clock_nanosleep_restart(struct restart_block *restart) { + clockid_t which_clock = restart->nanosleep.clockid; + struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + struct k_clock *kc = clockid_to_kclock(which_clock); long err; mm_segment_t oldfs; - struct timespec tu; - struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + struct __kernel_timespec tu; + + if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + return -EINVAL; + + restart->nanosleep.rmtp = (struct __kernel_timespec __user *) &tu;
- restart->nanosleep.rmtp = (struct timespec __user *) &tu; oldfs = get_fs(); set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); + err = kc->nsleep_restart(restart); set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) + (put_user(tu.tv_sec, &rmtp->tv_sec) || + put_user(tu.tv_nsec, &rmtp->tv_nsec))) return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) { @@ -1305,21 +1343,22 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, { long err; mm_segment_t oldfs; - struct timespec in, out; + struct timespec64 in; + struct __kernel_timespec out; struct restart_block *restart;
- if (compat_get_timespec(&in, rqtp)) + if (compat_get_timespec64(&in, rqtp)) return -EFAULT;
oldfs = get_fs(); set_fs(KERNEL_DS); - err = sys_clock_nanosleep(which_clock, flags, - (struct timespec __user *) &in, - (struct timespec __user *) &out); + err = clock_nanosleep(which_clock, flags, &in, + (struct __kernel_timespec __user *) &out); set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) + (put_user(out.tv_sec, &rmtp->tv_sec) || + put_user(out.tv_nsec, &rmtp->tv_nsec))) return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) {