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.ker...@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 = &current->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 = &current->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 = &current->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 = &current->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 = &current->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 = &current->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 = &current->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 = &current->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);
-- 
2.11.0

Reply via email to