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 <[email protected]>
---
 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 = &current->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) {
-- 
2.1.0.rc2

_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038

Reply via email to