mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-21 06:01:23 +00:00
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:
parent
99e6c0e6ec
commit
edbeda4632
8 changed files with 142 additions and 171 deletions
131
kernel/compat.c
131
kernel/compat.c
|
@ -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 = ¤t->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 = ¤t->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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue