From patchwork Mon Jun 19 06:45:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Deepa Dinamani X-Patchwork-Id: 9795275 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8F9136020B for ; Mon, 19 Jun 2017 06:47:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 77E5827E5A for ; Mon, 19 Jun 2017 06:47:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6C7EF27EE2; Mon, 19 Jun 2017 06:47:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 315EE27E5A for ; Mon, 19 Jun 2017 06:47:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753691AbdFSGrX (ORCPT ); Mon, 19 Jun 2017 02:47:23 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:33321 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753532AbdFSGpq (ORCPT ); Mon, 19 Jun 2017 02:45:46 -0400 Received: by mail-pf0-f195.google.com with SMTP id w12so15187199pfk.0; Sun, 18 Jun 2017 23:45:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=s4Tx20M/uw+Wxe0/B80gLaxd3ukfHhveX8Qav/w5c/o=; b=Rpb3hWzSxg6YOOqvk6ruM7b+KtlX8J/9IcEbGmA5qsyHCHxw147q5GgU8Gh3HZpYNc A1WiieuFKQK3ZPY6OFd+cCDYZoDQ27eR2E9ESSjXsYRVI9gZVyZJa25wXUZOTy4vlcmP yimNosRiK6b3BfbfcglYhYZ8jvkhH1J0F9mCu2lSd5FYGjvm8xL+HhqXAQ4c1vE97pH2 34LZytNNwSCH81KN3Sd76Y78FJVE1+m5X6b4UIm6HC6rDBXnVkULLzKBtaAkJTJ8y0kj x0xbGdGfdiyMwTLNLSPLYWHSObsn8WrEiq9U9n2rjxcJWBJtVwvNHZgT/8Eivm94YFD7 Lz5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=s4Tx20M/uw+Wxe0/B80gLaxd3ukfHhveX8Qav/w5c/o=; b=fJ6xq5Ii70H+5eRpO4ttXP++LdqydtJaR0ZHdFFvKJnz0PkWexKdW6CGAnqWljT1Ws fGHMGsAw4dO3wb27TEEVFeYI69kVMxqqCtoLoJAqq9+mrU+NI7zuDWCa6Ygk2MBLqywP f1WDRVn3Zq3I33TxsMi2B0/FVNjmpm7ZGL28xr2jZy/TIoPx9jyM1OLZKaEfYxZT7lG/ XBvwXnM5ee9g62n6cZYZUZEQFjpNQN+4Q/1RoQxftrfx5wZ90OvKlMKnEDoJCkzWGGh1 7XUaUxNNwK/EcaiIOVchHkT6D4rJ0pNNDH+88gpyJv37Zn9CJRo9xCMV8uAAlerMzKox eokA== X-Gm-Message-State: AKS2vOxZrHgC+9BPNasa4NKm1MGXREFe2sr5vsxI+msEs7kd8r6DZg6r xZ++gFwOCL2Miw== X-Received: by 10.98.144.132 with SMTP id q4mr23199337pfk.8.1497854745544; Sun, 18 Jun 2017 23:45:45 -0700 (PDT) Received: from localhost.localdomain ([2601:647:5000:6620:ecf7:aabb:b31b:424d]) by smtp.gmail.com with ESMTPSA id o66sm19620318pga.64.2017.06.18.23.45.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 18 Jun 2017 23:45:45 -0700 (PDT) From: Deepa Dinamani 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 Message-Id: <20170619064515.922-5-deepa.kernel@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170619064515.922-1-deepa.kernel@gmail.com> References: <20170619064515.922-1-deepa.kernel@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- include/linux/hrtimer.h | 5 +- kernel/time/Makefile | 2 +- kernel/time/alarmtimer.c | 26 +++------ kernel/time/hrtimer.c | 17 ++---- kernel/time/nanosleep.c | 130 +++++++++++++++++++++++++---------------- kernel/time/nanosleep.h | 19 ++++++ kernel/time/posix-cpu-timers.c | 27 ++++----- kernel/time/posix-stubs.c | 93 +++++++++++------------------ kernel/time/posix-timers.c | 105 +++++++++++++++------------------ kernel/time/posix-timers.h | 5 +- 10 files changed, 211 insertions(+), 218 deletions(-) create mode 100644 kernel/time/nanosleep.h diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 8c5b10eb7265..e1e6ca9a4db4 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -453,10 +453,11 @@ static inline u64 hrtimer_forward_now(struct hrtimer *timer, /* Precise sleep: */ extern long hrtimer_nanosleep(struct timespec64 *rqtp, - struct timespec __user *rmtp, + struct timespec64 *rmtp, const enum hrtimer_mode mode, const clockid_t clockid); -extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); +extern long hrtimer_nanosleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp); extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *tsk); diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 938dbf33ef49..0dee7cfc792b 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,4 +1,4 @@ -obj-y += time.o timer.o hrtimer.o +obj-y += time.o timer.o hrtimer.o nanosleep.o obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o obj-y += timeconv.o timecounter.o alarmtimer.o diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index d8a7a7e214de..567c9ca47974 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -710,28 +710,23 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) * update_rmtp - Update remaining timespec value * @exp: expiration time * @type: timer type - * @rmtp: user pointer to remaining timepsec value + * @rmtp: pointer to remaining timespec value * * Helper function that fills in rmtp value with time between * now and the exp value */ -static int update_rmtp(ktime_t exp, enum alarmtimer_type type, - struct timespec __user *rmtp) +static int update_rmtp(ktime_t exp, enum alarmtimer_type type, + struct timespec64 *rmtp) { - struct timespec rmt; ktime_t rem; rem = ktime_sub(exp, alarm_bases[type].gettime()); if (rem <= 0) return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + *rmtp = ktime_to_timespec64(rem); return 1; - } /** @@ -740,12 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type, * * Handles restarted clock_nanosleep calls */ -static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) +static long __sched alarm_timer_nsleep_restart(struct restart_block *restart, + struct timespec64 *rmtp) { enum alarmtimer_type type = restart->nanosleep.clockid; - ktime_t exp; - struct timespec __user *rmtp; struct alarm alarm; + ktime_t exp; int ret = 0; exp = restart->nanosleep.expires; @@ -757,14 +752,12 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) if (freezing(current)) alarmtimer_freezerset(exp, type); - rmtp = restart->nanosleep.rmtp; if (rmtp) { ret = update_rmtp(exp, type, rmtp); if (ret <= 0) goto out; } - /* The other values in restart are already filled in */ ret = -ERESTART_RESTARTBLOCK; out: @@ -782,7 +775,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) */ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, struct timespec64 *tsreq, - struct timespec __user *rmtp) + struct timespec64 *rmtp) { enum alarmtimer_type type = clock2alarm(which_clock); struct restart_block *restart; @@ -827,10 +820,8 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, } restart = ¤t->restart_block; - restart->fn = alarm_timer_nsleep_restart; restart->nanosleep.clockid = type; restart->nanosleep.expires = exp; - restart->nanosleep.rmtp = rmtp; ret = -ERESTART_RESTARTBLOCK; out: @@ -850,6 +841,7 @@ const struct k_clock alarm_clock = { .timer_remaining = alarm_timer_remaining, .timer_try_to_cancel = alarm_timer_try_to_cancel, .nsleep = alarm_timer_nsleep, + .nsleep_restart = alarm_timer_nsleep_restart, }; #endif /* CONFIG_POSIX_TIMERS */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index e95628910b00..a53857ca28b4 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1461,26 +1461,22 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod return t->task == NULL; } -static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) +static int update_rmtp(struct hrtimer *timer, struct timespec64 *rmtp) { - struct timespec rmt; ktime_t rem; rem = hrtimer_expires_remaining(timer); if (rem <= 0) return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; + *rmtp = ktime_to_timespec64(rem); return 1; } -long __sched hrtimer_nanosleep_restart(struct restart_block *restart) +long __sched hrtimer_nanosleep_restart(struct restart_block *restart, + struct timespec64 *rmtp) { struct hrtimer_sleeper t; - struct timespec __user *rmtp; int ret = 0; hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, @@ -1490,7 +1486,6 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) if (do_nanosleep(&t, HRTIMER_MODE_ABS)) goto out; - rmtp = restart->nanosleep.rmtp; if (rmtp) { ret = update_rmtp(&t.timer, rmtp); if (ret <= 0) @@ -1504,7 +1499,7 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart) return ret; } -long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, +long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec64 *rmtp, const enum hrtimer_mode mode, const clockid_t clockid) { struct restart_block *restart; @@ -1534,9 +1529,7 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, } restart = ¤t->restart_block; - restart->fn = hrtimer_nanosleep_restart; restart->nanosleep.clockid = t.timer.base->clockid; - restart->nanosleep.rmtp = rmtp; restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); ret = -ERESTART_RESTARTBLOCK; diff --git a/kernel/time/nanosleep.c b/kernel/time/nanosleep.c index 2b6e6980b65d..dd7d792b008b 100644 --- a/kernel/time/nanosleep.c +++ b/kernel/time/nanosleep.c @@ -1,64 +1,67 @@ -SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +#include +#include + +#include "nanosleep.h" + +long nanosleep_process_return(long ret, + const struct timespec64 *rmtp_kernel, + struct timespec __user *rmtp, + long (*fn)(struct restart_block *)) { - struct timespec64 tu64; - struct timespec tu; + struct restart_block *restart = ¤t->restart_block; - if (copy_from_user(&tu, rqtp, sizeof(tu))) + if ((ret == -ERESTART_RESTARTBLOCK) && rmtp && + put_timespec64(rmtp_kernel, rmtp)) return -EFAULT; - tu64 = timespec_to_timespec64(tu); - if (!timespec64_valid(&tu64)) - return -EINVAL; + if (ret == -ERESTART_RESTARTBLOCK) { + restart->nanosleep.rmtp = rmtp; + restart->fn = fn; + } - return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); + return ret; } -#ifdef CONFIG_COMPAT -static long compat_nanosleep_restart(struct restart_block *restart) +long nanosleep_restart(struct restart_block *restart_block) { - struct compat_timespec __user *rmtp; - struct timespec rmt; - mm_segment_t oldfs; + struct timespec __user *rmtp = restart_block->nanosleep.rmtp; + struct timespec64 rmt; long ret; - restart->nanosleep.rmtp = (struct timespec __user *) &rmt; - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep_restart(restart); - set_fs(oldfs); - - if (ret == -ERESTART_RESTARTBLOCK) { - rmtp = restart->nanosleep.compat_rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; - } + ret = hrtimer_nanosleep_restart(restart_block, + rmtp ? &rmt : NULL); - return ret; + return nanosleep_process_return(ret, &rmt, + rmtp, + nanosleep_restart); } -COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, - struct compat_timespec __user *, rmtp) +SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, + struct timespec __user *, rmtp) { - struct timespec tu, rmt; - struct timespec64 tu64; - mm_segment_t oldfs; - long ret; + struct timespec64 in; + struct timespec64 out; + int err; - if (compat_get_timespec(&tu, rqtp)) + if (get_timespec64(&in, rqtp)) return -EFAULT; - tu64 = timespec_to_timespec64(tu); - if (!timespec64_valid(&tu64)) + if (!timespec64_valid(&in)) return -EINVAL; - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = hrtimer_nanosleep(&tu64, - rmtp ? (struct timespec __user *)&rmt : NULL, + err = hrtimer_nanosleep(&in, rmtp ? &out : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC); - set_fs(oldfs); + + return nanosleep_process_return(err, &out, rmtp, nanosleep_restart); +} + +#ifdef CONFIG_COMPAT +long compat_nanosleep_process_return(long err, + struct timespec64 *rmt, + struct compat_timespec __user *rmtp, + long (*fn)(struct restart_block *)) +{ + struct restart_block *restart = ¤t->restart_block; /* * hrtimer_nanosleep() can only return 0 or @@ -79,16 +82,45 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, * We check for -ERESTART_RESTARTBLOCK nevertheless if the * core implementation decides to return random nonsense. */ - if (ret == -ERESTART_RESTARTBLOCK) { - struct restart_block *restart = ¤t->restart_block; + if ((err == -ERESTART_RESTARTBLOCK) && rmtp && + compat_put_timespec64(rmt, rmtp)) + return -EFAULT; - restart->fn = compat_nanosleep_restart; + if (err == -ERESTART_RESTARTBLOCK) { + restart->fn = fn; restart->nanosleep.compat_rmtp = rmtp; - - if (rmtp && compat_put_timespec(&rmt, rmtp)) - return -EFAULT; } - return ret; + return err; } -#endif +long compat_nanosleep_restart(struct restart_block *restart) +{ + struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + struct timespec64 kernel_rmt; + long ret; + + ret = hrtimer_nanosleep_restart(restart, rmtp ? &kernel_rmt : NULL); + + return compat_nanosleep_process_return(ret, &kernel_rmt, rmtp, + compat_nanosleep_restart); +} + +COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, + struct compat_timespec __user *, rmtp) +{ + struct timespec64 tu, rmt; + long ret; + + if (compat_get_timespec64(&tu, rqtp)) + return -EFAULT; + + if (!timespec64_valid(&tu)) + return -EINVAL; + + ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, + HRTIMER_MODE_REL, CLOCK_MONOTONIC); + + return compat_nanosleep_process_return(ret, &rmt, rmtp, + compat_nanosleep_restart); +} +#endif diff --git a/kernel/time/nanosleep.h b/kernel/time/nanosleep.h new file mode 100644 index 000000000000..68c924e0af14 --- /dev/null +++ b/kernel/time/nanosleep.h @@ -0,0 +1,19 @@ +#include + +long nanosleep_restart(struct restart_block *restart_block); + +long nanosleep_process_return(long ret, + const struct timespec64 *rmtp_kernel, + struct timespec __user *rmtp, + long (*fn)(struct restart_block *)); + + +#ifdef CONFIG_COMPAT +long compat_nanosleep_restart(struct restart_block *restart); + +long compat_nanosleep_process_return(long err, + struct timespec64 *rmt, + struct compat_timespec __user *rmtp, + long (*fn)(struct restart_block *)); + +#endif diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index cb4a4eb44279..24df407e2a6d 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -1310,14 +1310,14 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, return error; } -static long posix_cpu_nsleep_restart(struct restart_block *restart_block); +static long posix_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp); static int posix_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *rqtp, struct timespec __user *rmtp) + struct timespec64 *rqtp, struct timespec64 *rmtp) { struct restart_block *restart_block = ¤t->restart_block; struct itimerspec64 it; - struct timespec ts; int error; /* @@ -1337,24 +1337,20 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, /* * Report back to the user the time still remaining. */ - ts = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &ts, sizeof(*rmtp))) - return -EFAULT; + *rmtp = it.it_value; - restart_block->fn = posix_cpu_nsleep_restart; restart_block->nanosleep.clockid = which_clock; - restart_block->nanosleep.rmtp = rmtp; restart_block->nanosleep.expires = timespec64_to_ns(rqtp); } return error; } -static long posix_cpu_nsleep_restart(struct restart_block *restart_block) +static long posix_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *rmtp) { clockid_t which_clock = restart_block->nanosleep.clockid; struct itimerspec64 it; struct timespec64 t; - struct timespec tmp; int error; t = ns_to_timespec64(restart_block->nanosleep.expires); @@ -1362,14 +1358,10 @@ static long posix_cpu_nsleep_restart(struct restart_block *restart_block) error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); if (error == -ERESTART_RESTARTBLOCK) { - struct timespec __user *rmtp = restart_block->nanosleep.rmtp; /* * Report back to the user the time still remaining. */ - tmp = timespec64_to_timespec(it.it_value); - if (rmtp && copy_to_user(rmtp, &tmp, sizeof(*rmtp))) - return -EFAULT; - + *rmtp = it.it_value; restart_block->nanosleep.expires = timespec64_to_ns(&t); } return error; @@ -1396,11 +1388,12 @@ static int process_cpu_timer_create(struct k_itimer *timer) } static int process_cpu_nsleep(const clockid_t which_clock, int flags, struct timespec64 *rqtp, - struct timespec __user *rmtp) + struct timespec64 *rmtp) { return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); } -static long process_cpu_nsleep_restart(struct restart_block *restart_block) +static long process_cpu_nsleep_restart(struct restart_block *restart_block, + struct timespec64 *tp) { return -EINVAL; } diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index cd1b9a2e2618..61daf3576e85 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include +#include "nanosleep.h" + asmlinkage long sys_ni_posix_timers(void) { pr_err_once("process %d (%s) attempted a POSIX timer syscall " @@ -100,28 +103,44 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __us } } -SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, - const struct timespec __user *, rqtp, - struct timespec __user *, rmtp) +static long do_clock_nanosleep(const clockid_t which_clock, + int flags, + struct timespec64 *rqtp, + struct timespec64 *rmtp) { - struct timespec64 t64; - struct timespec t; + long ret; switch (which_clock) { case CLOCK_REALTIME: case CLOCK_MONOTONIC: case CLOCK_BOOTTIME: - if (copy_from_user(&t, rqtp, sizeof (struct timespec))) - return -EFAULT; - t64 = timespec_to_timespec64(t); - if (!timespec64_valid(&t64)) + if (!timespec64_valid(rqtp)) return -EINVAL; - return hrtimer_nanosleep(&t64, rmtp, flags & TIMER_ABSTIME ? + ret = hrtimer_nanosleep(rqtp, rmtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); + break; default: return -EINVAL; } + + return ret; +} + +SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, + const struct timespec __user *, rqtp, + struct timespec __user *, rmtp) +{ + struct timespec64 in, out; + struct timespec64 *rtn = rmtp ? &out : NULL; + long ret; + + if (get_timespec64(&in, rqtp)) + return -EFAULT; + + ret = do_clock_nanosleep(which_clock, flags, &in, rtn); + + return nanosleep_process_return(ret, rtn, rmtp, nanosleep_restart); } #ifdef CONFIG_COMPAT @@ -180,63 +199,19 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, return err; } -long clock_nanosleep_restart(struct restart_block *restart_block) -{ - return hrtimer_nanosleep_restart(restart_block); -} - -static long compat_clock_nanosleep_restart(struct restart_block *restart) -{ - long err; - mm_segment_t oldfs; - struct timespec tu; - struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; - - restart->nanosleep.rmtp = (struct timespec __user *) &tu; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) - return -EFAULT; - - if (err == -ERESTART_RESTARTBLOCK) { - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; -} - COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { + struct timespec64 in, out; long err; - mm_segment_t oldfs; - struct timespec in, out; - struct restart_block *restart; - if (compat_get_timespec(&in, rqtp)) + if (compat_get_timespec64(&in, rqtp)) return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_nanosleep(which_clock, flags, - (struct timespec __user *) &in, - (struct timespec __user *) &out); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) - return -EFAULT; + err = do_clock_nanosleep(which_clock, flags, &in, &out); - if (err == -ERESTART_RESTARTBLOCK) { - restart = ¤t->restart_block; - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &out, rmtp, + compat_nanosleep_restart); } #endif diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 009a9145d64d..58c2f9c2c2c8 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include "timekeeping.h" #include "posix-timers.h" +#include "nanosleep.h" /* * Management arrays for POSIX timers. Timers are now kept in static hash table @@ -1027,49 +1029,52 @@ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, * nanosleep for monotonic and realtime clocks */ static int common_nsleep(const clockid_t which_clock, int flags, - struct timespec64 *tsave, struct timespec __user *rmtp) + struct timespec64 *tsave, struct timespec64 *rmtp) { return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL, which_clock); } +long clock_nanosleep_restart(struct restart_block *restart_block) +{ + clockid_t which_clock = restart_block->nanosleep.clockid; + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 rmt; + long ret; + + if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + return -EINVAL; + + ret = kc->nsleep_restart(restart_block, + restart_block->nanosleep.rmtp ? &rmt : NULL); + return nanosleep_process_return(ret, &rmt, + restart_block->nanosleep.rmtp, + clock_nanosleep_restart); +} + SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, const struct timespec __user *, rqtp, struct timespec __user *, rmtp) { const struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec64 t64; - struct timespec t; + struct timespec64 in, out; + long err; if (!kc) return -EINVAL; if (!kc->nsleep) return -ENANOSLEEP_NOTSUP; - if (copy_from_user(&t, rqtp, sizeof (struct timespec))) + if (get_timespec64(&in, rqtp)) return -EFAULT; - t64 = timespec_to_timespec64(t); - if (!timespec64_valid(&t64)) + if (!timespec64_valid(&in)) return -EINVAL; - return kc->nsleep(which_clock, flags, &t64, rmtp); -} - -/* - * This will restart clock_nanosleep. This is required only by - * compat_clock_nanosleep_restart for now. - */ -long clock_nanosleep_restart(struct restart_block *restart_block) -{ - clockid_t which_clock = restart_block->nanosleep.clockid; - const struct k_clock *kc = clockid_to_kclock(which_clock); - - if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) - return -EINVAL; - - return kc->nsleep_restart(restart_block); + err = kc->nsleep(which_clock, flags, &in, rmtp ? &out : NULL); + return nanosleep_process_return(err, &out, rmtp, + clock_nanosleep_restart); } static const struct k_clock clock_realtime = { @@ -1181,57 +1186,40 @@ static const struct k_clock *clockid_to_kclock(const clockid_t id) #ifdef CONFIG_COMPAT static long compat_clock_nanosleep_restart(struct restart_block *restart) { - long err; - mm_segment_t oldfs; - struct timespec tu; struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp; + clockid_t which_clock = restart->nanosleep.clockid; + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 rmt; + long err; - restart->nanosleep.rmtp = (struct timespec __user *) &tu; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = clock_nanosleep_restart(restart); - set_fs(oldfs); + if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) + return -EINVAL; - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&tu, rmtp)) - return -EFAULT; + err = kc->nsleep_restart(restart, rmtp ? &rmt : NULL); - if (err == -ERESTART_RESTARTBLOCK) { - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &rmt, rmtp, + compat_clock_nanosleep_restart); } COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, struct compat_timespec __user *, rqtp, struct compat_timespec __user *, rmtp) { + const struct k_clock *kc = clockid_to_kclock(which_clock); + struct timespec64 in, out; long err; - mm_segment_t oldfs; - struct timespec in, out; - struct restart_block *restart; - if (compat_get_timespec(&in, rqtp)) + if (compat_get_timespec64(&in, rqtp)) return -EFAULT; - oldfs = get_fs(); - set_fs(KERNEL_DS); - err = sys_clock_nanosleep(which_clock, flags, - (struct timespec __user *) &in, - (struct timespec __user *) &out); - set_fs(oldfs); - - if ((err == -ERESTART_RESTARTBLOCK) && rmtp && - compat_put_timespec(&out, rmtp)) - return -EFAULT; + if (!kc) + return -EINVAL; + if (!kc->nsleep) + return -ENANOSLEEP_NOTSUP; + err = kc->nsleep(which_clock, flags, &in, rmtp ? &out : NULL); - if (err == -ERESTART_RESTARTBLOCK) { - restart = ¤t->restart_block; - restart->fn = compat_clock_nanosleep_restart; - restart->nanosleep.compat_rmtp = rmtp; - } - return err; + return compat_nanosleep_process_return(err, &out, rmtp, + compat_clock_nanosleep_restart); } COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, @@ -1324,5 +1312,4 @@ COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, return -EFAULT; return err; } - #endif diff --git a/kernel/time/posix-timers.h b/kernel/time/posix-timers.h index b086f5ba2f5b..85a3f34593df 100644 --- a/kernel/time/posix-timers.h +++ b/kernel/time/posix-timers.h @@ -10,8 +10,9 @@ struct k_clock { int (*clock_adj)(const clockid_t which_clock, struct timex *tx); int (*timer_create)(struct k_itimer *timer); int (*nsleep)(const clockid_t which_clock, int flags, - struct timespec64 *, struct timespec __user *); - long (*nsleep_restart)(struct restart_block *restart_block); + struct timespec64 *, struct timespec64 *); + long (*nsleep_restart)(struct restart_block *restart_block, + struct timespec64 *); int (*timer_set)(struct k_itimer *timr, int flags, struct itimerspec64 *new_setting, struct itimerspec64 *old_setting);