Move nanosleep syscall to a new file that is compiled
unconditionally. This helps share common nanosleep code
between posix-timers and posix-stubs. The latter part
is addressed in subsequent patches in the series.

In this series, this also servers as a preparatory patch
to eliminate the use of set_fs()/get_fs() in the compat
syscall path.

Note that the clock_nanosleep compat syscalls have to be moved
twice, once into each file: posix_timers.c and posix-stubs.c.

Signed-off-by: Deepa Dinamani <deepa.ker...@gmail.com>
---
 kernel/compat.c            | 131 ---------------------------------------------
 kernel/time/hrtimer.c      |  17 +-----
 kernel/time/nanosleep.c    |  94 ++++++++++++++++++++++++++++++++
 kernel/time/posix-stubs.c  |  56 +++++++++++++++++++
 kernel/time/posix-timers.c |  58 ++++++++++++++++++++
 5 files changed, 209 insertions(+), 147 deletions(-)
 create mode 100644 kernel/time/nanosleep.c

diff --git a/kernel/compat.c b/kernel/compat.c
index c7a01a01222d..89d10cf47e9c 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -257,82 +257,6 @@ int compat_convert_timespec(struct timespec __user **kts,
        return 0;
 }
 
-static long compat_nanosleep_restart(struct restart_block *restart)
-{
-       struct compat_timespec __user *rmtp;
-       struct timespec rmt;
-       mm_segment_t oldfs;
-       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;
-       }
-
-       return ret;
-}
-
-COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
-                      struct compat_timespec __user *, rmtp)
-{
-       struct timespec tu, rmt;
-       struct timespec64 tu64;
-       mm_segment_t oldfs;
-       long ret;
-
-       if (compat_get_timespec(&tu, rqtp))
-               return -EFAULT;
-
-       tu64 = timespec_to_timespec64(tu);
-       if (!timespec64_valid(&tu64))
-               return -EINVAL;
-
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = hrtimer_nanosleep(&tu64,
-                               rmtp ? (struct timespec __user *)&rmt : NULL,
-                               HRTIMER_MODE_REL, CLOCK_MONOTONIC);
-       set_fs(oldfs);
-
-       /*
-        * hrtimer_nanosleep() can only return 0 or
-        * -ERESTART_RESTARTBLOCK here because:
-        *
-        * - we call it with HRTIMER_MODE_REL and therefor exclude the
-        *   -ERESTARTNOHAND return path.
-        *
-        * - we supply the rmtp argument from the task stack (due to
-        *   the necessary compat conversion. So the update cannot
-        *   fail, which excludes the -EFAULT return path as well. If
-        *   it fails nevertheless we have a bigger problem and wont
-        *   reach this place anymore.
-        *
-        * - if the return value is 0, we do not have to update rmtp
-        *    because there is no remaining time.
-        *
-        * 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;
-
-               restart->fn = compat_nanosleep_restart;
-               restart->nanosleep.compat_rmtp = rmtp;
-
-               if (rmtp && compat_put_timespec(&rmt, rmtp))
-                       return -EFAULT;
-       }
-       return ret;
-}
-
 static inline long get_compat_itimerval(struct itimerval *o,
                struct compat_itimerval __user *i)
 {
@@ -865,61 +789,6 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, 
which_clock,
        return err;
 }
 
-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)
-{
-       long err;
-       mm_segment_t oldfs;
-       struct timespec in, out;
-       struct restart_block *restart;
-
-       if (compat_get_timespec(&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 (err == -ERESTART_RESTARTBLOCK) {
-               restart = &current->restart_block;
-               restart->fn = compat_clock_nanosleep_restart;
-               restart->nanosleep.compat_rmtp = rmtp;
-       }
-       return err;
-}
-
 /*
  * We currently only need the following fields from the sigevent
  * structure: sigev_value, sigev_signo, sig_notify and (sometimes
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index ac053bb5296e..e95628910b00 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -37,6 +37,7 @@
 #include <linux/hrtimer.h>
 #include <linux/notifier.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 #include <linux/tick.h>
@@ -1544,22 +1545,6 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct 
timespec __user *rmtp,
        return ret;
 }
 
-SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
-               struct timespec __user *, rmtp)
-{
-       struct timespec64 tu64;
-       struct timespec tu;
-
-       if (copy_from_user(&tu, rqtp, sizeof(tu)))
-               return -EFAULT;
-
-       tu64 = timespec_to_timespec64(tu);
-       if (!timespec64_valid(&tu64))
-               return -EINVAL;
-
-       return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, 
CLOCK_MONOTONIC);
-}
-
 /*
  * Functions related to boot-time initialization:
  */
diff --git a/kernel/time/nanosleep.c b/kernel/time/nanosleep.c
new file mode 100644
index 000000000000..2b6e6980b65d
--- /dev/null
+++ b/kernel/time/nanosleep.c
@@ -0,0 +1,94 @@
+SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
+               struct timespec __user *, rmtp)
+{
+       struct timespec64 tu64;
+       struct timespec tu;
+
+       if (copy_from_user(&tu, rqtp, sizeof(tu)))
+               return -EFAULT;
+
+       tu64 = timespec_to_timespec64(tu);
+       if (!timespec64_valid(&tu64))
+               return -EINVAL;
+
+       return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, 
CLOCK_MONOTONIC);
+}
+
+#ifdef CONFIG_COMPAT
+static long compat_nanosleep_restart(struct restart_block *restart)
+{
+       struct compat_timespec __user *rmtp;
+       struct timespec rmt;
+       mm_segment_t oldfs;
+       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;
+       }
+
+       return ret;
+}
+
+COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
+                      struct compat_timespec __user *, rmtp)
+{
+       struct timespec tu, rmt;
+       struct timespec64 tu64;
+       mm_segment_t oldfs;
+       long ret;
+
+       if (compat_get_timespec(&tu, rqtp))
+               return -EFAULT;
+
+       tu64 = timespec_to_timespec64(tu);
+       if (!timespec64_valid(&tu64))
+               return -EINVAL;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = hrtimer_nanosleep(&tu64,
+                               rmtp ? (struct timespec __user *)&rmt : NULL,
+                               HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+       set_fs(oldfs);
+
+       /*
+        * hrtimer_nanosleep() can only return 0 or
+        * -ERESTART_RESTARTBLOCK here because:
+        *
+        * - we call it with HRTIMER_MODE_REL and therefor exclude the
+        *   -ERESTARTNOHAND return path.
+        *
+        * - we supply the rmtp argument from the task stack (due to
+        *   the necessary compat conversion. So the update cannot
+        *   fail, which excludes the -EFAULT return path as well. If
+        *   it fails nevertheless we have a bigger problem and wont
+        *   reach this place anymore.
+        *
+        * - if the return value is 0, we do not have to update rmtp
+        *    because there is no remaining time.
+        *
+        * 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;
+
+               restart->fn = compat_nanosleep_restart;
+               restart->nanosleep.compat_rmtp = rmtp;
+
+               if (rmtp && compat_put_timespec(&rmt, rmtp))
+                       return -EFAULT;
+       }
+       return ret;
+}
+#endif
+
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c
index c0cd53eb018a..3031a28921ba 100644
--- a/kernel/time/posix-stubs.c
+++ b/kernel/time/posix-stubs.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <linux/ktime.h>
 #include <linux/timekeeping.h>
 #include <linux/posix-timers.h>
@@ -128,4 +129,59 @@ 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)
+{
+       long err;
+       mm_segment_t oldfs;
+       struct timespec in, out;
+       struct restart_block *restart;
+
+       if (compat_get_timespec(&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 (err == -ERESTART_RESTARTBLOCK) {
+               restart = &current->restart_block;
+               restart->fn = compat_clock_nanosleep_restart;
+               restart->nanosleep.compat_rmtp = rmtp;
+       }
+       return err;
+}
 #endif
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 6e7a70b1bf37..cf32adccd062 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -45,6 +45,7 @@
 #include <linux/posix-clock.h>
 #include <linux/posix-timers.h>
 #include <linux/syscalls.h>
+#include <linux/compat.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/export.h>
@@ -1176,3 +1177,60 @@ static const struct k_clock *clockid_to_kclock(const 
clockid_t id)
                return NULL;
        return posix_clocks[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;
+
+       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)
+{
+       long err;
+       mm_segment_t oldfs;
+       struct timespec in, out;
+       struct restart_block *restart;
+
+       if (compat_get_timespec(&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 (err == -ERESTART_RESTARTBLOCK) {
+               restart = &current->restart_block;
+               restart->fn = compat_clock_nanosleep_restart;
+               restart->nanosleep.compat_rmtp = rmtp;
+       }
+       return err;
+}
+#endif
-- 
2.11.0

Reply via email to