All of lore.kernel.org
 help / color / mirror / Atom feed
From: Deepa Dinamani <deepa.kernel@gmail.com>
To: tglx@linutronix.de, viro@zeniv.linux.org.uk,
	linux-kernel@vger.kernel.org
Cc: john.stultz@linaro.org, nicolas.pitre@linaro.org, arnd@arndb.de,
	y2038@lists.linaro.org, linux-fsdevel@vger.kernel.org
Subject: [PATCH 4/8] nanosleep: Use get_timespec64() and set_timespec64()
Date: Sun, 18 Jun 2017 23:45:11 -0700	[thread overview]
Message-ID: <20170619064515.922-5-deepa.kernel@gmail.com> (raw)
In-Reply-To: <20170619064515.922-1-deepa.kernel@gmail.com>

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 = &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

  parent reply	other threads:[~2017-06-19  6:45 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-19  6:45 [PATCH 0/8] Isolate time_t data types for clock/timer syscalls Deepa Dinamani
2017-06-19  6:45 ` [PATCH 1/8] time: add get_timespec64 and put_timespec64 Deepa Dinamani
2017-06-19  6:45 ` [PATCH 2/8] nanosleep: Move native and compat syscalls Deepa Dinamani
2017-06-19  6:45 ` [PATCH 3/8] kernel: compat: Move clock and timer " Deepa Dinamani
2017-06-19  6:45 ` Deepa Dinamani [this message]
2017-06-19  6:45 ` [PATCH 5/8] posix-timers: Use get_timepsec64() and put_timespec64() Deepa Dinamani
2017-06-19  6:45 ` [PATCH 6/8] time: introduce {get,put}_itimerspec64 Deepa Dinamani
2017-06-19  6:45 ` [PATCH 7/8] posix_clocks: Use get_itimerspec64() and put_itimerspec64() Deepa Dinamani
2017-06-19  6:45 ` [PATCH 8/8] timerfd: " Deepa Dinamani
2017-06-19  7:25 ` [PATCH 0/8] Isolate time_t data types for clock/timer syscalls Al Viro
2017-06-19 19:31   ` Deepa Dinamani
2017-06-19 19:46     ` Al Viro
2017-06-19 20:52       ` Deepa Dinamani
2017-06-19 21:12         ` Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170619064515.922-5-deepa.kernel@gmail.com \
    --to=deepa.kernel@gmail.com \
    --cc=arnd@arndb.de \
    --cc=john.stultz@linaro.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicolas.pitre@linaro.org \
    --cc=tglx@linutronix.de \
    --cc=viro@zeniv.linux.org.uk \
    --cc=y2038@lists.linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.