Commit 86a9c446 authored by Al Viro's avatar Al Viro Committed by Thomas Gleixner

posix-cpu-timers: Move copyout of timespec into do_cpu_nanosleep()

The posix-cpu-timer nanosleep() implementation can be simplified by moving
the copy out of the remaining time to do_cpu_nanosleep() which is shared
between the real nanosleep function and the restart function.

The pointer to the timespec64 which is updated has to be stored in the
restart block anyway. Instead of storing it only in the restart case, store
it before calling do_cpu_nanosleep() and copy the remaining time in the
signal exit path.

[ tglx: Added changelog ]
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170607084241.28657-1-viro@ZenIV.linux.org.uk
parent 67edab48
...@@ -1226,9 +1226,10 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, ...@@ -1226,9 +1226,10 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
} }
static int do_cpu_nanosleep(const clockid_t which_clock, int flags, static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
struct timespec64 *rqtp, struct itimerspec64 *it) struct timespec64 *rqtp)
{ {
struct k_itimer timer; struct k_itimer timer;
struct itimerspec64 it;
int error; int error;
/* /*
...@@ -1242,12 +1243,14 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1242,12 +1243,14 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
timer.it_process = current; timer.it_process = current;
if (!error) { if (!error) {
static struct itimerspec64 zero_it; static struct itimerspec64 zero_it;
struct restart_block *restart = &current->restart_block;
struct timespec __user *rmtp;
memset(it, 0, sizeof *it); memset(&it, 0, sizeof it);
it->it_value = *rqtp; it.it_value = *rqtp;
spin_lock_irq(&timer.it_lock); spin_lock_irq(&timer.it_lock);
error = posix_cpu_timer_set(&timer, flags, it, NULL); error = posix_cpu_timer_set(&timer, flags, &it, NULL);
if (error) { if (error) {
spin_unlock_irq(&timer.it_lock); spin_unlock_irq(&timer.it_lock);
return error; return error;
...@@ -1277,7 +1280,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1277,7 +1280,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
* We were interrupted by a signal. * We were interrupted by a signal.
*/ */
*rqtp = ns_to_timespec64(timer.it.cpu.expires); *rqtp = ns_to_timespec64(timer.it.cpu.expires);
error = posix_cpu_timer_set(&timer, 0, &zero_it, it); error = posix_cpu_timer_set(&timer, 0, &zero_it, &it);
if (!error) { if (!error) {
/* /*
* Timer is now unarmed, deletion can not fail. * Timer is now unarmed, deletion can not fail.
...@@ -1297,7 +1300,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1297,7 +1300,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
spin_unlock_irq(&timer.it_lock); spin_unlock_irq(&timer.it_lock);
} }
if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
/* /*
* It actually did fire already. * It actually did fire already.
*/ */
...@@ -1305,6 +1308,18 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, ...@@ -1305,6 +1308,18 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
} }
error = -ERESTART_RESTARTBLOCK; error = -ERESTART_RESTARTBLOCK;
/*
* Report back to the user the time still remaining.
*/
rmtp = restart->nanosleep.rmtp;
if (rmtp) {
struct timespec ts;
ts = timespec64_to_timespec(it.it_value);
if (copy_to_user(rmtp, &ts, sizeof(*rmtp)))
return -EFAULT;
}
restart->nanosleep.expires = timespec64_to_ns(rqtp);
} }
return error; return error;
...@@ -1316,10 +1331,13 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1316,10 +1331,13 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
struct timespec64 *rqtp, struct timespec __user *rmtp) struct timespec64 *rqtp, struct timespec __user *rmtp)
{ {
struct restart_block *restart_block = &current->restart_block; struct restart_block *restart_block = &current->restart_block;
struct itimerspec64 it;
struct timespec ts;
int error; int error;
if (flags & TIMER_ABSTIME)
rmtp = NULL;
restart_block->nanosleep.rmtp = rmtp;
/* /*
* Diagnose required errors first. * Diagnose required errors first.
*/ */
...@@ -1328,23 +1346,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1328,23 +1346,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
CPUCLOCK_PID(which_clock) == task_pid_vnr(current))) CPUCLOCK_PID(which_clock) == task_pid_vnr(current)))
return -EINVAL; return -EINVAL;
error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); error = do_cpu_nanosleep(which_clock, flags, rqtp);
if (error == -ERESTART_RESTARTBLOCK) { if (error == -ERESTART_RESTARTBLOCK) {
if (flags & TIMER_ABSTIME) if (flags & TIMER_ABSTIME)
return -ERESTARTNOHAND; return -ERESTARTNOHAND;
/*
* 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;
restart_block->fn = posix_cpu_nsleep_restart; restart_block->fn = posix_cpu_nsleep_restart;
restart_block->nanosleep.clockid = which_clock; restart_block->nanosleep.clockid = which_clock;
restart_block->nanosleep.rmtp = rmtp;
restart_block->nanosleep.expires = timespec64_to_ns(rqtp);
} }
return error; return error;
} }
...@@ -1352,28 +1362,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags, ...@@ -1352,28 +1362,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
static long posix_cpu_nsleep_restart(struct restart_block *restart_block) static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
{ {
clockid_t which_clock = restart_block->nanosleep.clockid; clockid_t which_clock = restart_block->nanosleep.clockid;
struct itimerspec64 it;
struct timespec64 t; struct timespec64 t;
struct timespec tmp;
int error;
t = ns_to_timespec64(restart_block->nanosleep.expires); t = ns_to_timespec64(restart_block->nanosleep.expires);
error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); return do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t);
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;
restart_block->nanosleep.expires = timespec64_to_ns(&t);
}
return error;
} }
#define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED) #define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment