Skip to content

Commit

Permalink
posix-timers: Take compat timer_settime(2) to native one
Browse files Browse the repository at this point in the history
... and get rid of set_fs() in there

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
  • Loading branch information
Al Viro authored and KAGA-KOKO committed Jun 13, 2017
1 parent 3a4d44b commit 1acbe77
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 47 deletions.
23 changes: 0 additions & 23 deletions kernel/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,29 +635,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
return sys_timer_create(which_clock, event, created_timer_id);
}

COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
struct compat_itimerspec __user *, new,
struct compat_itimerspec __user *, old)
{
long err;
mm_segment_t oldfs;
struct itimerspec newts, oldts;

if (!new)
return -EINVAL;
if (get_compat_itimerspec(&newts, new))
return -EFAULT;
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_timer_settime(timer_id, flags,
(struct itimerspec __user *) &newts,
(struct itimerspec __user *) &oldts);
set_fs(oldfs);
if (!err && old && put_compat_itimerspec(old, &oldts))
return -EFAULT;
return err;
}

COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
struct compat_itimerspec __user *, setting)
{
Expand Down
1 change: 1 addition & 0 deletions kernel/time/posix-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SYS_NI(setitimer);
SYS_NI(alarm);
#endif
COMPAT_SYS_NI(clock_adjtime);
COMPAT_SYS_NI(timer_settime);

/*
* We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
Expand Down
87 changes: 63 additions & 24 deletions kernel/time/posix-timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,31 +819,21 @@ int common_timer_set(struct k_itimer *timr, int flags,
return 0;
}

/* Set a POSIX.1b interval timer */
SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
const struct itimerspec __user *, new_setting,
struct itimerspec __user *, old_setting)
static int do_timer_settime(timer_t timer_id, int flags,
struct itimerspec64 *new_spec64,
struct itimerspec64 *old_spec64)
{
struct itimerspec64 new_spec64, old_spec64;
struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL;
struct itimerspec new_spec, old_spec;
const struct k_clock *kc;
struct k_itimer *timr;
unsigned long flag;
const struct k_clock *kc;
int error = 0;

if (!new_setting)
if (!timespec64_valid(&new_spec64->it_interval) ||
!timespec64_valid(&new_spec64->it_value))
return -EINVAL;

if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
return -EFAULT;
new_spec64 = itimerspec_to_itimerspec64(&new_spec);

if (!timespec64_valid(&new_spec64.it_interval) ||
!timespec64_valid(&new_spec64.it_value))
return -EINVAL;
if (rtn)
memset(rtn, 0, sizeof(*rtn));
if (old_spec64)
memset(old_spec64, 0, sizeof(*old_spec64));
retry:
timr = lock_timer(timer_id, &flag);
if (!timr)
Expand All @@ -853,22 +843,71 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
if (WARN_ON_ONCE(!kc || !kc->timer_set))
error = -EINVAL;
else
error = kc->timer_set(timr, flags, &new_spec64, rtn);
error = kc->timer_set(timr, flags, new_spec64, old_spec64);

unlock_timer(timr, flag);
if (error == TIMER_RETRY) {
rtn = NULL; // We already got the old time...
old_spec64 = NULL; // We already got the old time...
goto retry;
}

old_spec = itimerspec64_to_itimerspec(&old_spec64);
if (old_setting && !error &&
copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
error = -EFAULT;
return error;
}

/* Set a POSIX.1b interval timer */
SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
const struct itimerspec __user *, new_setting,
struct itimerspec __user *, old_setting)
{
struct itimerspec64 new_spec64, old_spec64;
struct itimerspec64 *rtn = old_setting ? &old_spec64 : NULL;
struct itimerspec new_spec;
int error = 0;

if (!new_setting)
return -EINVAL;

if (copy_from_user(&new_spec, new_setting, sizeof (new_spec)))
return -EFAULT;
new_spec64 = itimerspec_to_itimerspec64(&new_spec);

error = do_timer_settime(timer_id, flags, &new_spec64, rtn);
if (!error && old_setting) {
struct itimerspec old_spec;
old_spec = itimerspec64_to_itimerspec(&old_spec64);
if (copy_to_user(old_setting, &old_spec, sizeof (old_spec)))
error = -EFAULT;
}
return error;
}

#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
struct compat_itimerspec __user *, new,
struct compat_itimerspec __user *, old)
{
struct itimerspec64 new_spec64, old_spec64;
struct itimerspec64 *rtn = old ? &old_spec64 : NULL;
struct itimerspec new_spec;
int error = 0;

if (!new)
return -EINVAL;
if (get_compat_itimerspec(&new_spec, new))
return -EFAULT;

new_spec64 = itimerspec_to_itimerspec64(&new_spec);
error = do_timer_settime(timer_id, flags, &new_spec64, rtn);
if (!error && old) {
struct itimerspec old_spec;
old_spec = itimerspec64_to_itimerspec(&old_spec64);
if (put_compat_itimerspec(old, &old_spec))
error = -EFAULT;
}
return error;
}
#endif

int common_timer_del(struct k_itimer *timer)
{
const struct k_clock *kc = timer->kclock;
Expand Down

0 comments on commit 1acbe77

Please sign in to comment.