Usage of these apis and their compat versions makes the sys_nanosleep() and sys_compat_nanosleep() implementations simpler.
This patch also serves as a preparatory patch for changing syscalls to use new time_t data types to support the y2038 effort by eliminating the processing of user pointers down the call stack.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- include/linux/hrtimer.h | 5 +- kernel/time/Makefile | 2 +- kernel/time/alarmtimer.c | 26 +++------ kernel/time/hrtimer.c | 17 ++---- kernel/time/nanosleep.c | 130 +++++++++++++++++++++++++---------------- kernel/time/nanosleep.h | 19 ++++++ kernel/time/posix-cpu-timers.c | 27 ++++----- kernel/time/posix-stubs.c | 93 +++++++++++------------------ kernel/time/posix-timers.c | 105 +++++++++++++++------------------ kernel/time/posix-timers.h | 5 +- 10 files changed, 211 insertions(+), 218 deletions(-) create mode 100644 kernel/time/nanosleep.h
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 8c5b10eb7265..e1e6ca9a4db4 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -453,10 +453,11 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer,
/* Precise sleep: */ extern long hrtimer_nanosleep(struct timespec64 *rqtp, - struct timespec __user *rmtp, + struct timespec64 *rmtp, const enum hrtimer_mode mode, const clockid_t clockid); -extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); +extern long hrtimer_nanosleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp);
extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *tsk); diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 938dbf33ef49..0dee7cfc792b 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,4 +1,4 @@ -obj-y += time.o timer.o hrtimer.o +obj-y += time.o timer.o hrtimer.o nanosleep.o obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o obj-y += timeconv.o timecounter.o alarmtimer.o
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index d8a7a7e214de..567c9ca47974 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -710,28 +710,23 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) * update_rmtp - Update remaining timespec value * @exp: expiration time * @type: timer type - * @rmtp: user pointer to remaining timepsec value + * @rmtp: pointer to remaining timespec value * * Helper function that fills in rmtp value with time between * now and the exp value */ -static int update_rmtp(ktime_t exp, enum alarmtimer_type type, - struct timespec __user *rmtp) +static int update_rmtp(ktime_t exp, enum alarmtimer_type type, + struct timespec64 *rmtp) { - struct timespec rmt; ktime_t rem;
rem = ktime_sub(exp, alarm_bases[type].gettime());
if (rem <= 0) return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + *rmtp = ktime_to_timespec64(rem);
return 1; - }
/** @@ -740,12 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type, * * Handles restarted clock_nanosleep calls */ -static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) +static long __sched alarm_timer_nsleep_restart(struct restart_block *restart, + struct timespec64 *rmtp) { enum alarmtimer_type type = restart->nanosleep.clockid; - ktime_t exp; - struct timespec __user *rmtp; struct alarm alarm; + ktime_t exp; int ret = 0;
exp = restart->nanosleep.expires; @@ -757,14 +752,12 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) if (freezing(current)) alarmtimer_freezerset(exp, type);
- rmtp = restart->nanosleep.rmtp; if (rmtp) { ret = update_rmtp(exp, type, rmtp); if (ret <= 0) goto out; }
- /* The other values in restart are already filled in */ ret = -ERESTART_RESTARTBLOCK; out: @@ -782,7 +775,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) */ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, struct timespec64 *tsreq, - struct timespec __user *rmtp) + struct timespec64 *rmtp) { enum alarmtimer_type type = clock2alarm(which_clock); struct restart_block *restart; @@ -827,10 +820,8 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, }
restart = ¤t->restart_block; - restart->fn = alarm_timer_nsleep_restart; restart->nanosleep.clockid = type; restart->nanosleep.expires = exp; - restart->nanosleep.rmtp = rmtp; ret = -ERESTART_RESTARTBLOCK;
out: @@ -850,6 +841,7 @@ const struct k_clock alarm_clock = { .timer_remaining = alarm_timer_remaining, .timer_try_to_cancel = alarm_timer_try_to_cancel, .nsleep = alarm_timer_nsleep, + .nsleep_restart = alarm_timer_nsleep_restart, }; #endif /* CONFIG_POSIX_TIMERS */
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index e95628910b00..a53857ca28b4 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1461,26 +1461,22 @@ 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 timespec64 *rmtp) { - struct timespec rmt; ktime_t rem;
rem = hrtimer_expires_remaining(timer); if (rem <= 0) return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + *rmtp = ktime_to_timespec64(rem);
return 1; }
-long __sched hrtimer_nanosleep_restart(struct restart_block *restart) +long __sched hrtimer_nanosleep_restart(struct restart_block *restart, + struct timespec64 *rmtp) { struct hrtimer_sleeper t; - struct timespec __user *rmtp; int ret = 0;
hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, @@ -1490,7 +1486,6 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) if (do_nanosleep(&t, HRTIMER_MODE_ABS)) goto out;
- rmtp = restart->nanosleep.rmtp; if (rmtp) { ret = update_rmtp(&t.timer, rmtp); if (ret <= 0) @@ -1504,7 +1499,7 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) return ret; }
-long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, +long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec64 *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; @@ -1534,9 +1529,7 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, }
restart = ¤t->restart_block; - restart->fn = hrtimer_nanosleep_restart; restart->nanosleep.clockid = t.timer.base->clockid; - restart->nanosleep.rmtp = rmtp; restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
ret = -ERESTART_RESTARTBLOCK; diff --git a/kernel/time/nanosleep.c b/kernel/time/nanosleep.c index 2b6e6980b65d..dd7d792b008b 100644 --- a/kernel/time/nanosleep.c +++ b/kernel/time/nanosleep.c @@ -1,64 +1,67 @@ -SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +#include <linux/syscalls.h> +#include <linux/compat.h> + +#include "nanosleep.h" + +long nanosleep_process_return(long ret, + const struct timespec64 *rmtp_kernel, + struct timespec __user *rmtp, + long (*fn)(struct restart_block *)) { - struct timespec64 tu64; - struct timespec tu; + struct restart_block *restart = ¤t->restart_block;
- if (copy_from_user(&tu, rqtp, sizeof(tu))) + if ((ret == -ERESTART_RESTARTBLOCK) && rmtp && + put_timespec64(rmtp_kernel, rmtp)) return -EFAULT;
- tu64 = timespec_to_timespec64(tu); - if (!timespec64_valid(&tu64)) - return -EINVAL; + if (ret == -ERESTART_RESTARTBLOCK) { + restart->nanosleep.rmtp = rmtp; + restart->fn = fn; + }
- return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); + return ret; }
-#ifdef CONFIG_COMPAT -static long compat_nanosleep_restart(struct restart_block *restart) +long nanosleep_restart(struct restart_block *restart_block) { - struct compat_timespec __user *rmtp; - struct timespec rmt; - mm_segment_t oldfs; + struct timespec __user *rmtp = restart_block->nanosleep.rmtp; + struct timespec64 rmt; long ret;
- restart->nanosleep.rmtp = (struct timespec __user *) &rmt; - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep_restart(restart); - set_fs(oldfs); - - if (ret == -ERESTART_RESTARTBLOCK) { - rmtp = restart->nanosleep.compat_rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; - } + ret = hrtimer_nanosleep_restart(restart_block, + rmtp ? &rmt : NULL);
- return ret; + return nanosleep_process_return(ret, &rmt, + rmtp, + nanosleep_restart); }
-COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) +SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, + struct timespec __user *, rmtp) { - struct timespec tu, rmt; - struct timespec64 tu64; - mm_segment_t oldfs; - long ret; + struct timespec64 in; + struct timespec64 out; + int err;
- if (compat_get_timespec(&tu, rqtp)) + if (get_timespec64(&in, rqtp)) return -EFAULT;
- tu64 = timespec_to_timespec64(tu); - if (!timespec64_valid(&tu64)) + if (!timespec64_valid(&in)) return -EINVAL;
- oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep(&tu64, - rmtp ? (struct timespec __user *)&rmt : NULL, + err = hrtimer_nanosleep(&in, rmtp ? &out : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC); - set_fs(oldfs); + + return nanosleep_process_return(err, &out, rmtp, nanosleep_restart); +} + +#ifdef CONFIG_COMPAT +long compat_nanosleep_process_return(long err, + struct timespec64 *rmt, + struct compat_timespec __user *rmtp, + long (*fn)(struct restart_block *)) +{ + struct restart_block *restart = ¤t->restart_block;
/* * hrtimer_nanosleep() can only return 0 or @@ -79,16 +82,45 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, * We check for -ERESTART_RESTARTBLOCK nevertheless if the * core implementation decides to return random nonsense. */ - if (ret == -ERESTART_RESTARTBLOCK) { - struct restart_block *restart = ¤t->restart_block; + if ((err == -ERESTART_RESTARTBLOCK) && rmtp && + compat_put_timespec64(rmt, rmtp)) + return -EFAULT;
- restart->fn = compat_nanosleep_restart; + if (err == -ERESTART_RESTARTBLOCK) { + restart->fn = fn; restart->nanosleep.compat_rmtp = rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; } - return ret; + return err; } -#endif
+long compat_nanosleep_restart(struct restart_block *restart) +{ + struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + struct timespec64 kernel_rmt; + long ret; + + ret = hrtimer_nanosleep_restart(restart, rmtp ? &kernel_rmt : NULL); + + return compat_nanosleep_process_return(ret, &kernel_rmt, rmtp, + compat_nanosleep_restart); +} + +COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, + struct compat_timespec __user *, rmtp) +{ + struct timespec64 tu, rmt; + long ret; + + if (compat_get_timespec64(&tu, rqtp)) + return -EFAULT; + + if (!timespec64_valid(&tu)) + return -EINVAL; + + ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, + HRTIMER_MODE_REL, CLOCK_MONOTONIC); + + return compat_nanosleep_process_return(ret, &rmt, rmtp, + compat_nanosleep_restart); +} +#endif diff --git a/kernel/time/nanosleep.h b/kernel/time/nanosleep.h new file mode 100644 index 000000000000..68c924e0af14 --- /dev/null +++ b/kernel/time/nanosleep.h @@ -0,0 +1,19 @@ +#include <linux/compat.h> + +long nanosleep_restart(struct restart_block *restart_block); + +long nanosleep_process_return(long ret, + const struct timespec64 *rmtp_kernel, + struct timespec __user *rmtp, + long (*fn)(struct restart_block *)); + + +#ifdef CONFIG_COMPAT +long compat_nanosleep_restart(struct restart_block *restart); + +long compat_nanosleep_process_return(long err, + struct timespec64 *rmt, + struct compat_timespec __user *rmtp, + long (*fn)(struct restart_block *)); + +#endif diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index cb4a4eb44279..24df407e2a6d 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -1310,14 +1310,14 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, return error; }
-static long posix_cpu_nsleep_restart(struct restart_block *restart_block); +static long posix_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp);
static int posix_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *rqtp, struct timespec __user *rmtp) + struct timespec64 *rqtp, struct timespec64 *rmtp) { struct restart_block *restart_block = ¤t->restart_block; struct itimerspec64 it; - struct timespec ts; int error;
/* @@ -1337,24 +1337,20 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, /* * Report back to the user the time still remaining. */ - ts = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &ts, sizeof(*rmtp))) - return -EFAULT; + *rmtp = it.it_value;
- restart_block->fn = posix_cpu_nsleep_restart; restart_block->nanosleep.clockid = which_clock; - restart_block->nanosleep.rmtp = rmtp; restart_block->nanosleep.expires = timespec64_to_ns(rqtp); } return error; }
-static long posix_cpu_nsleep_restart(struct restart_block *restart_block) +static long posix_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp) { clockid_t which_clock = restart_block->nanosleep.clockid; struct itimerspec64 it; struct timespec64 t; - struct timespec tmp; int error;
t = ns_to_timespec64(restart_block->nanosleep.expires); @@ -1362,14 +1358,10 @@ 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; /* * Report back to the user the time still remaining. */ - tmp = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &tmp, sizeof(*rmtp))) - return -EFAULT; - + *rmtp = it.it_value; restart_block->nanosleep.expires = timespec64_to_ns(&t); } return error; @@ -1396,11 +1388,12 @@ static int process_cpu_timer_create(struct k_itimer *timer) } static int process_cpu_nsleep(const clockid_t which_clock, int flags, struct timespec64 *rqtp, - struct timespec __user *rmtp) + struct timespec64 *rmtp) { return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); } -static long process_cpu_nsleep_restart(struct restart_block *restart_block) +static long process_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *tp) { return -EINVAL; } diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index cd1b9a2e2618..61daf3576e85 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c @@ -11,6 +11,7 @@
#include <linux/linkage.h> #include <linux/kernel.h> +#include <linux/compat.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/syscalls.h> @@ -19,6 +20,8 @@ #include <linux/timekeeping.h> #include <linux/posix-timers.h>
+#include "nanosleep.h" + asmlinkage long sys_ni_posix_timers(void) { pr_err_once("process %d (%s) attempted a POSIX timer syscall " @@ -100,28 +103,44 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __us } }
-SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, - const struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +static long do_clock_nanosleep(const clockid_t which_clock, + int flags, + struct timespec64 *rqtp, + struct timespec64 *rmtp) { - struct timespec64 t64; - struct timespec t; + long ret;
switch (which_clock) { case CLOCK_REALTIME: case CLOCK_MONOTONIC: case CLOCK_BOOTTIME: - if (copy_from_user(&t, rqtp, sizeof (struct timespec))) - return -EFAULT; - t64 = timespec_to_timespec64(t); - if (!timespec64_valid(&t64)) + if (!timespec64_valid(rqtp)) return -EINVAL; - return hrtimer_nanosleep(&t64, rmtp, flags & TIMER_ABSTIME ? + ret = hrtimer_nanosleep(rqtp, rmtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); + break; default: return -EINVAL; } + + return ret; +} + +SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, + const struct timespec __user *, rqtp, + struct timespec __user *, rmtp) +{ + struct timespec64 in, out; + struct timespec64 *rtn = rmtp ? &out : NULL; + long ret; + + if (get_timespec64(&in, rqtp)) + return -EFAULT; + + ret = do_clock_nanosleep(which_clock, flags, &in, rtn); + + return nanosleep_process_return(ret, rtn, rmtp, nanosleep_restart); }
#ifdef CONFIG_COMPAT @@ -180,63 +199,19 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, return err; }
-long clock_nanosleep_restart(struct restart_block *restart_block) -{ - return hrtimer_nanosleep_restart(restart_block); -} - -static long compat_clock_nanosleep_restart(struct restart_block *restart) -{ - long err; - mm_segment_t oldfs; - struct timespec tu; - struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; - - restart->nanosleep.rmtp = (struct timespec __user *) &tu; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) - return -EFAULT; - - if (err == -ERESTART_RESTARTBLOCK) { - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; -} - COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { + struct timespec64 in, out; long err; - mm_segment_t oldfs; - struct timespec in, 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); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) - return -EFAULT; + err = do_clock_nanosleep(which_clock, flags, &in, &out);
- if (err == -ERESTART_RESTARTBLOCK) { - restart = ¤t->restart_block; - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &out, rmtp, + compat_nanosleep_restart); } #endif diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 009a9145d64d..58c2f9c2c2c8 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -37,6 +37,7 @@ #include <linux/mutex.h> #include <linux/sched/task.h>
+#include <linux/compat.h> #include <linux/uaccess.h> #include <linux/list.h> #include <linux/init.h> @@ -53,6 +54,7 @@
#include "timekeeping.h" #include "posix-timers.h" +#include "nanosleep.h"
/* * Management arrays for POSIX timers. Timers are now kept in static hash table @@ -1027,49 +1029,52 @@ 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 timespec64 *tsave, struct timespec __user *rmtp) + struct timespec64 *tsave, struct timespec64 *rmtp) { return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); }
+long clock_nanosleep_restart(struct restart_block *restart_block) +{ + clockid_t which_clock = restart_block->nanosleep.clockid; + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 rmt; + long ret; + + if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + return -EINVAL; + + ret = kc->nsleep_restart(restart_block, + restart_block->nanosleep.rmtp ? &rmt : NULL); + return nanosleep_process_return(ret, &rmt, + restart_block->nanosleep.rmtp, + clock_nanosleep_restart); +} + SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, const struct timespec __user *, rqtp, struct timespec __user *, rmtp) { const struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec64 t64; - struct timespec t; + struct timespec64 in, out; + long err;
if (!kc) return -EINVAL; if (!kc->nsleep) return -ENANOSLEEP_NOTSUP;
- if (copy_from_user(&t, rqtp, sizeof (struct timespec))) + if (get_timespec64(&in, rqtp)) return -EFAULT;
- t64 = timespec_to_timespec64(t); - if (!timespec64_valid(&t64)) + if (!timespec64_valid(&in)) return -EINVAL;
- return kc->nsleep(which_clock, flags, &t64, rmtp); -} - -/* - * This will restart clock_nanosleep. This is required only by - * compat_clock_nanosleep_restart for now. - */ -long clock_nanosleep_restart(struct restart_block *restart_block) -{ - clockid_t which_clock = restart_block->nanosleep.clockid; - const struct k_clock *kc = clockid_to_kclock(which_clock); - - if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) - return -EINVAL; - - return kc->nsleep_restart(restart_block); + err = kc->nsleep(which_clock, flags, &in, rmtp ? &out : NULL); + return nanosleep_process_return(err, &out, rmtp, + clock_nanosleep_restart); }
static const struct k_clock clock_realtime = { @@ -1181,57 +1186,40 @@ static const struct k_clock *clockid_to_kclock(const clockid_t id) #ifdef CONFIG_COMPAT static long compat_clock_nanosleep_restart(struct restart_block *restart) { - long err; - mm_segment_t oldfs; - struct timespec tu; struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + clockid_t which_clock = restart->nanosleep.clockid; + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 rmt; + long err;
- restart->nanosleep.rmtp = (struct timespec __user *) &tu; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); - set_fs(oldfs); + if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + return -EINVAL;
- if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) - return -EFAULT; + err = kc->nsleep_restart(restart, rmtp ? &rmt : NULL);
- if (err == -ERESTART_RESTARTBLOCK) { - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &rmt, rmtp, + compat_clock_nanosleep_restart); }
COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 in, out; long err; - mm_segment_t oldfs; - struct timespec in, 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); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) - return -EFAULT; + if (!kc) + return -EINVAL; + if (!kc->nsleep) + return -ENANOSLEEP_NOTSUP; + err = kc->nsleep(which_clock, flags, &in, rmtp ? &out : NULL);
- if (err == -ERESTART_RESTARTBLOCK) { - restart = ¤t->restart_block; - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &out, rmtp, + compat_clock_nanosleep_restart); }
COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, @@ -1324,5 +1312,4 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, return -EFAULT; return err; } - #endif diff --git a/kernel/time/posix-timers.h b/kernel/time/posix-timers.h index b086f5ba2f5b..85a3f34593df 100644 --- a/kernel/time/posix-timers.h +++ b/kernel/time/posix-timers.h @@ -10,8 +10,9 @@ struct k_clock { 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 timespec64 *, struct timespec __user *); - long (*nsleep_restart)(struct restart_block *restart_block); + struct timespec64 *, struct timespec64 *); + long (*nsleep_restart)(struct restart_block *restart_block, + struct timespec64 *); int (*timer_set)(struct k_itimer *timr, int flags, struct itimerspec64 *new_setting, struct itimerspec64 *old_setting);