time/posix-timers: Move the compat copyouts to the nanosleep implementations

Turn restart_block.nanosleep.{rmtp,compat_rmtp} into a tagged union (kind =
1 -> native, kind = 2 -> compat, kind = 0 -> nothing) and make the places
doing actual copyout handle compat as well as native (that will become a
helper in the next commit).  Result: compat wrappers, messing with
reassignments, etc. are gone.

[ tglx: Folded in a variant of Peter Zijlstras enum patch ]

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Thomas 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-6-viro@ZenIV.linux.org.uk
This commit is contained in:
Al Viro 2017-06-07 09:42:31 +01:00 committed by Thomas Gleixner
parent 99e6c0e6ec
commit edbeda4632
8 changed files with 142 additions and 171 deletions

View file

@ -213,82 +213,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);
current->restart_block.nanosleep.rmtp =
rmtp ? (struct timespec __user *)&rmt : NULL;
ret = hrtimer_nanosleep(&tu64, 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)
{
@ -821,61 +745,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