Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner:
"A rather large update for timers/timekeeping:
- compat syscall consolidation (Al Viro)
- Posix timer consolidation (Christoph Helwig / Thomas Gleixner)
- Cleanup of the device tree based initialization for clockevents and
clocksources (Daniel Lezcano)
- Consolidation of the FTTMR010 clocksource/event driver (Linus
Walleij)
- The usual set of small fixes and updates all over the place"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (93 commits)
timers: Make the cpu base lock raw
clocksource/drivers/mips-gic-timer: Fix an error code in 'gic_clocksource_of_init()'
clocksource/drivers/fsl_ftm_timer: Unmap region obtained by of_iomap
clocksource/drivers/tcb_clksrc: Make IO endian agnostic
clocksource/drivers/sun4i: Switch to the timer-of common init
clocksource/drivers/timer-of: Fix invalid iomap check
Revert "ktime: Simplify ktime_compare implementation"
clocksource/drivers: Fix uninitialized variable use in timer_of_init
kselftests: timers: Add test for frequency step
kselftests: timers: Fix inconsistency-check to not ignore first timestamp
time: Add warning about imminent deprecation of CONFIG_GENERIC_TIME_VSYSCALL_OLD
time: Clean up CLOCK_MONOTONIC_RAW time handling
posix-cpu-timers: Make timespec to nsec conversion safe
itimer: Make timeval to nsec conversion range limited
timers: Fix parameter description of try_to_del_timer_sync()
ktime: Simplify ktime_compare implementation
clocksource/drivers/fttmr010: Factor out clock read code
clocksource/drivers/fttmr010: Implement delay timer
clocksource/drivers: Add timer-of common init routine
clocksource/drivers/tcb_clksrc: Save timer context on suspend/resume
...
This commit is contained in:
528
kernel/compat.c
528
kernel/compat.c
@@ -30,102 +30,68 @@
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
|
||||
int compat_get_timex(struct timex *txc, const struct compat_timex __user *utp)
|
||||
{
|
||||
memset(txc, 0, sizeof(struct timex));
|
||||
struct compat_timex tx32;
|
||||
|
||||
if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
|
||||
__get_user(txc->modes, &utp->modes) ||
|
||||
__get_user(txc->offset, &utp->offset) ||
|
||||
__get_user(txc->freq, &utp->freq) ||
|
||||
__get_user(txc->maxerror, &utp->maxerror) ||
|
||||
__get_user(txc->esterror, &utp->esterror) ||
|
||||
__get_user(txc->status, &utp->status) ||
|
||||
__get_user(txc->constant, &utp->constant) ||
|
||||
__get_user(txc->precision, &utp->precision) ||
|
||||
__get_user(txc->tolerance, &utp->tolerance) ||
|
||||
__get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
|
||||
__get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
|
||||
__get_user(txc->tick, &utp->tick) ||
|
||||
__get_user(txc->ppsfreq, &utp->ppsfreq) ||
|
||||
__get_user(txc->jitter, &utp->jitter) ||
|
||||
__get_user(txc->shift, &utp->shift) ||
|
||||
__get_user(txc->stabil, &utp->stabil) ||
|
||||
__get_user(txc->jitcnt, &utp->jitcnt) ||
|
||||
__get_user(txc->calcnt, &utp->calcnt) ||
|
||||
__get_user(txc->errcnt, &utp->errcnt) ||
|
||||
__get_user(txc->stbcnt, &utp->stbcnt))
|
||||
if (copy_from_user(&tx32, utp, sizeof(struct compat_timex)))
|
||||
return -EFAULT;
|
||||
|
||||
txc->modes = tx32.modes;
|
||||
txc->offset = tx32.offset;
|
||||
txc->freq = tx32.freq;
|
||||
txc->maxerror = tx32.maxerror;
|
||||
txc->esterror = tx32.esterror;
|
||||
txc->status = tx32.status;
|
||||
txc->constant = tx32.constant;
|
||||
txc->precision = tx32.precision;
|
||||
txc->tolerance = tx32.tolerance;
|
||||
txc->time.tv_sec = tx32.time.tv_sec;
|
||||
txc->time.tv_usec = tx32.time.tv_usec;
|
||||
txc->tick = tx32.tick;
|
||||
txc->ppsfreq = tx32.ppsfreq;
|
||||
txc->jitter = tx32.jitter;
|
||||
txc->shift = tx32.shift;
|
||||
txc->stabil = tx32.stabil;
|
||||
txc->jitcnt = tx32.jitcnt;
|
||||
txc->calcnt = tx32.calcnt;
|
||||
txc->errcnt = tx32.errcnt;
|
||||
txc->stbcnt = tx32.stbcnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
|
||||
int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc)
|
||||
{
|
||||
if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
|
||||
__put_user(txc->modes, &utp->modes) ||
|
||||
__put_user(txc->offset, &utp->offset) ||
|
||||
__put_user(txc->freq, &utp->freq) ||
|
||||
__put_user(txc->maxerror, &utp->maxerror) ||
|
||||
__put_user(txc->esterror, &utp->esterror) ||
|
||||
__put_user(txc->status, &utp->status) ||
|
||||
__put_user(txc->constant, &utp->constant) ||
|
||||
__put_user(txc->precision, &utp->precision) ||
|
||||
__put_user(txc->tolerance, &utp->tolerance) ||
|
||||
__put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
|
||||
__put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
|
||||
__put_user(txc->tick, &utp->tick) ||
|
||||
__put_user(txc->ppsfreq, &utp->ppsfreq) ||
|
||||
__put_user(txc->jitter, &utp->jitter) ||
|
||||
__put_user(txc->shift, &utp->shift) ||
|
||||
__put_user(txc->stabil, &utp->stabil) ||
|
||||
__put_user(txc->jitcnt, &utp->jitcnt) ||
|
||||
__put_user(txc->calcnt, &utp->calcnt) ||
|
||||
__put_user(txc->errcnt, &utp->errcnt) ||
|
||||
__put_user(txc->stbcnt, &utp->stbcnt) ||
|
||||
__put_user(txc->tai, &utp->tai))
|
||||
struct compat_timex tx32;
|
||||
|
||||
memset(&tx32, 0, sizeof(struct compat_timex));
|
||||
tx32.modes = txc->modes;
|
||||
tx32.offset = txc->offset;
|
||||
tx32.freq = txc->freq;
|
||||
tx32.maxerror = txc->maxerror;
|
||||
tx32.esterror = txc->esterror;
|
||||
tx32.status = txc->status;
|
||||
tx32.constant = txc->constant;
|
||||
tx32.precision = txc->precision;
|
||||
tx32.tolerance = txc->tolerance;
|
||||
tx32.time.tv_sec = txc->time.tv_sec;
|
||||
tx32.time.tv_usec = txc->time.tv_usec;
|
||||
tx32.tick = txc->tick;
|
||||
tx32.ppsfreq = txc->ppsfreq;
|
||||
tx32.jitter = txc->jitter;
|
||||
tx32.shift = txc->shift;
|
||||
tx32.stabil = txc->stabil;
|
||||
tx32.jitcnt = txc->jitcnt;
|
||||
tx32.calcnt = txc->calcnt;
|
||||
tx32.errcnt = txc->errcnt;
|
||||
tx32.stbcnt = txc->stbcnt;
|
||||
tx32.tai = txc->tai;
|
||||
if (copy_to_user(utp, &tx32, sizeof(struct compat_timex)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
if (tv) {
|
||||
struct timeval ktv;
|
||||
do_gettimeofday(&ktv);
|
||||
if (compat_put_timeval(&ktv, tv))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (tz) {
|
||||
if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
struct timespec64 new_ts;
|
||||
struct timeval user_tv;
|
||||
struct timezone new_tz;
|
||||
|
||||
if (tv) {
|
||||
if (compat_get_timeval(&user_tv, tv))
|
||||
return -EFAULT;
|
||||
new_ts.tv_sec = user_tv.tv_sec;
|
||||
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
|
||||
}
|
||||
if (tz) {
|
||||
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
||||
}
|
||||
|
||||
static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
|
||||
{
|
||||
return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
|
||||
@@ -213,143 +179,30 @@ int compat_convert_timespec(struct timespec __user **kts,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long compat_nanosleep_restart(struct restart_block *restart)
|
||||
int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i)
|
||||
{
|
||||
struct compat_timespec __user *rmtp;
|
||||
struct timespec rmt;
|
||||
mm_segment_t oldfs;
|
||||
long ret;
|
||||
struct compat_itimerval v32;
|
||||
|
||||
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);
|
||||
ret = hrtimer_nanosleep(&tu64,
|
||||
rmtp ? (struct timespec __user *)&rmt : NULL,
|
||||
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)
|
||||
{
|
||||
return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
|
||||
(__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
|
||||
__get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
|
||||
__get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
|
||||
__get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
|
||||
}
|
||||
|
||||
static inline long put_compat_itimerval(struct compat_itimerval __user *o,
|
||||
struct itimerval *i)
|
||||
{
|
||||
return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
|
||||
(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
|
||||
__put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
|
||||
__put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
|
||||
__put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
|
||||
}
|
||||
|
||||
asmlinkage long sys_ni_posix_timers(void);
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
|
||||
struct compat_itimerval __user *, it)
|
||||
{
|
||||
struct itimerval kit;
|
||||
int error;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
|
||||
return sys_ni_posix_timers();
|
||||
|
||||
error = do_getitimer(which, &kit);
|
||||
if (!error && put_compat_itimerval(it, &kit))
|
||||
error = -EFAULT;
|
||||
return error;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
|
||||
struct compat_itimerval __user *, in,
|
||||
struct compat_itimerval __user *, out)
|
||||
{
|
||||
struct itimerval kin, kout;
|
||||
int error;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
|
||||
return sys_ni_posix_timers();
|
||||
|
||||
if (in) {
|
||||
if (get_compat_itimerval(&kin, in))
|
||||
return -EFAULT;
|
||||
} else
|
||||
memset(&kin, 0, sizeof(kin));
|
||||
|
||||
error = do_setitimer(which, &kin, out ? &kout : NULL);
|
||||
if (error || !out)
|
||||
return error;
|
||||
if (put_compat_itimerval(out, &kout))
|
||||
if (copy_from_user(&v32, i, sizeof(struct compat_itimerval)))
|
||||
return -EFAULT;
|
||||
o->it_interval.tv_sec = v32.it_interval.tv_sec;
|
||||
o->it_interval.tv_usec = v32.it_interval.tv_usec;
|
||||
o->it_value.tv_sec = v32.it_value.tv_sec;
|
||||
o->it_value.tv_usec = v32.it_value.tv_usec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i)
|
||||
{
|
||||
struct compat_itimerval v32;
|
||||
|
||||
v32.it_interval.tv_sec = i->it_interval.tv_sec;
|
||||
v32.it_interval.tv_usec = i->it_interval.tv_usec;
|
||||
v32.it_value.tv_sec = i->it_value.tv_sec;
|
||||
v32.it_value.tv_usec = i->it_value.tv_usec;
|
||||
return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
|
||||
{
|
||||
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
|
||||
@@ -689,193 +542,6 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
|
||||
struct compat_sigevent __user *, timer_event_spec,
|
||||
timer_t __user *, created_timer_id)
|
||||
{
|
||||
struct sigevent __user *event = NULL;
|
||||
|
||||
if (timer_event_spec) {
|
||||
struct sigevent kevent;
|
||||
|
||||
event = compat_alloc_user_space(sizeof(*event));
|
||||
if (get_compat_sigevent(&kevent, timer_event_spec) ||
|
||||
copy_to_user(event, &kevent, sizeof(*event)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
long err;
|
||||
mm_segment_t oldfs;
|
||||
struct itimerspec ts;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
err = sys_timer_gettime(timer_id,
|
||||
(struct itimerspec __user *) &ts);
|
||||
set_fs(oldfs);
|
||||
if (!err && put_compat_itimerspec(setting, &ts))
|
||||
return -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
long err;
|
||||
mm_segment_t oldfs;
|
||||
struct timespec ts;
|
||||
|
||||
if (compat_get_timespec(&ts, tp))
|
||||
return -EFAULT;
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
err = sys_clock_settime(which_clock,
|
||||
(struct timespec __user *) &ts);
|
||||
set_fs(oldfs);
|
||||
return err;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
long err;
|
||||
mm_segment_t oldfs;
|
||||
struct timespec ts;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
err = sys_clock_gettime(which_clock,
|
||||
(struct timespec __user *) &ts);
|
||||
set_fs(oldfs);
|
||||
if (!err && compat_put_timespec(&ts, tp))
|
||||
return -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
|
||||
struct compat_timex __user *, utp)
|
||||
{
|
||||
struct timex txc;
|
||||
mm_segment_t oldfs;
|
||||
int err, ret;
|
||||
|
||||
err = compat_get_timex(&txc, utp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
|
||||
set_fs(oldfs);
|
||||
|
||||
err = compat_put_timex(utp, &txc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
long err;
|
||||
mm_segment_t oldfs;
|
||||
struct timespec ts;
|
||||
|
||||
oldfs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
err = sys_clock_getres(which_clock,
|
||||
(struct timespec __user *) &ts);
|
||||
set_fs(oldfs);
|
||||
if (!err && tp && compat_put_timespec(&ts, tp))
|
||||
return -EFAULT;
|
||||
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
|
||||
@@ -1035,64 +701,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __ARCH_WANT_COMPAT_SYS_TIME
|
||||
|
||||
/* compat_time_t is a 32 bit "long" and needs to get converted. */
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
|
||||
{
|
||||
compat_time_t i;
|
||||
struct timeval tv;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
i = tv.tv_sec;
|
||||
|
||||
if (tloc) {
|
||||
if (put_user(i,tloc))
|
||||
return -EFAULT;
|
||||
}
|
||||
force_successful_syscall_return();
|
||||
return i;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
|
||||
{
|
||||
struct timespec tv;
|
||||
int err;
|
||||
|
||||
if (get_user(tv.tv_sec, tptr))
|
||||
return -EFAULT;
|
||||
|
||||
tv.tv_nsec = 0;
|
||||
|
||||
err = security_settime(&tv, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do_settimeofday(&tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)
|
||||
{
|
||||
struct timex txc;
|
||||
int err, ret;
|
||||
|
||||
err = compat_get_timex(&txc, utp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ret = do_adjtimex(&txc);
|
||||
|
||||
err = compat_put_timex(utp, &txc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
|
||||
compat_uptr_t __user *, pages32,
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/cn_proc.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/posix-timers.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/signal.h>
|
||||
@@ -637,7 +638,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
||||
* about to disable them again anyway.
|
||||
*/
|
||||
spin_unlock(&tsk->sighand->siglock);
|
||||
do_schedule_next_timer(info);
|
||||
posixtimer_rearm(info);
|
||||
spin_lock(&tsk->sighand->siglock);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "posix-timers.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/alarmtimer.h>
|
||||
@@ -45,11 +48,13 @@ static struct alarm_base {
|
||||
clockid_t base_clockid;
|
||||
} alarm_bases[ALARM_NUMTYPE];
|
||||
|
||||
#if defined(CONFIG_POSIX_TIMERS) || defined(CONFIG_RTC_CLASS)
|
||||
/* freezer information to handle clock_nanosleep triggered wakeups */
|
||||
static enum alarmtimer_type freezer_alarmtype;
|
||||
static ktime_t freezer_expires;
|
||||
static ktime_t freezer_delta;
|
||||
static DEFINE_SPINLOCK(freezer_delta_lock);
|
||||
#endif
|
||||
|
||||
static struct wakeup_source *ws;
|
||||
|
||||
@@ -307,38 +312,6 @@ static int alarmtimer_resume(struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
|
||||
{
|
||||
struct alarm_base *base;
|
||||
unsigned long flags;
|
||||
ktime_t delta;
|
||||
|
||||
switch(type) {
|
||||
case ALARM_REALTIME:
|
||||
base = &alarm_bases[ALARM_REALTIME];
|
||||
type = ALARM_REALTIME_FREEZER;
|
||||
break;
|
||||
case ALARM_BOOTTIME:
|
||||
base = &alarm_bases[ALARM_BOOTTIME];
|
||||
type = ALARM_BOOTTIME_FREEZER;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid alarm type: %d\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
delta = ktime_sub(absexp, base->gettime());
|
||||
|
||||
spin_lock_irqsave(&freezer_delta_lock, flags);
|
||||
if (!freezer_delta || (delta < freezer_delta)) {
|
||||
freezer_delta = delta;
|
||||
freezer_expires = absexp;
|
||||
freezer_alarmtype = type;
|
||||
}
|
||||
spin_unlock_irqrestore(&freezer_delta_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* alarm_init - Initialize an alarm structure
|
||||
* @alarm: ptr to alarm to be initialized
|
||||
@@ -488,6 +461,38 @@ u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alarm_forward_now);
|
||||
|
||||
#ifdef CONFIG_POSIX_TIMERS
|
||||
|
||||
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
|
||||
{
|
||||
struct alarm_base *base;
|
||||
unsigned long flags;
|
||||
ktime_t delta;
|
||||
|
||||
switch(type) {
|
||||
case ALARM_REALTIME:
|
||||
base = &alarm_bases[ALARM_REALTIME];
|
||||
type = ALARM_REALTIME_FREEZER;
|
||||
break;
|
||||
case ALARM_BOOTTIME:
|
||||
base = &alarm_bases[ALARM_BOOTTIME];
|
||||
type = ALARM_BOOTTIME_FREEZER;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid alarm type: %d\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
delta = ktime_sub(absexp, base->gettime());
|
||||
|
||||
spin_lock_irqsave(&freezer_delta_lock, flags);
|
||||
if (!freezer_delta || (delta < freezer_delta)) {
|
||||
freezer_delta = delta;
|
||||
freezer_expires = absexp;
|
||||
freezer_alarmtype = type;
|
||||
}
|
||||
spin_unlock_irqrestore(&freezer_delta_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* clock2alarm - helper that converts from clockid to alarmtypes
|
||||
@@ -511,22 +516,26 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid)
|
||||
static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
|
||||
ktime_t now)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct k_itimer *ptr = container_of(alarm, struct k_itimer,
|
||||
it.alarm.alarmtimer);
|
||||
it.alarm.alarmtimer);
|
||||
enum alarmtimer_restart result = ALARMTIMER_NORESTART;
|
||||
unsigned long flags;
|
||||
int si_private = 0;
|
||||
|
||||
spin_lock_irqsave(&ptr->it_lock, flags);
|
||||
if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) {
|
||||
if (IS_ENABLED(CONFIG_POSIX_TIMERS) &&
|
||||
posix_timer_event(ptr, 0) != 0)
|
||||
ptr->it_overrun++;
|
||||
}
|
||||
|
||||
/* Re-add periodic timers */
|
||||
if (ptr->it.alarm.interval) {
|
||||
ptr->it_overrun += alarm_forward(alarm, now,
|
||||
ptr->it.alarm.interval);
|
||||
ptr->it_active = 0;
|
||||
if (ptr->it_interval)
|
||||
si_private = ++ptr->it_requeue_pending;
|
||||
|
||||
if (posix_timer_event(ptr, si_private) && ptr->it_interval) {
|
||||
/*
|
||||
* Handle ignored signals and rearm the timer. This will go
|
||||
* away once we handle ignored signals proper.
|
||||
*/
|
||||
ptr->it_overrun += alarm_forward_now(alarm, ptr->it_interval);
|
||||
++ptr->it_requeue_pending;
|
||||
ptr->it_active = 1;
|
||||
result = ALARMTIMER_RESTART;
|
||||
}
|
||||
spin_unlock_irqrestore(&ptr->it_lock, flags);
|
||||
@@ -534,6 +543,72 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_rearm - Posix timer callback for rearming timer
|
||||
* @timr: Pointer to the posixtimer data struct
|
||||
*/
|
||||
static void alarm_timer_rearm(struct k_itimer *timr)
|
||||
{
|
||||
struct alarm *alarm = &timr->it.alarm.alarmtimer;
|
||||
|
||||
timr->it_overrun += alarm_forward_now(alarm, timr->it_interval);
|
||||
alarm_start(alarm, alarm->node.expires);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_forward - Posix timer callback for forwarding timer
|
||||
* @timr: Pointer to the posixtimer data struct
|
||||
* @now: Current time to forward the timer against
|
||||
*/
|
||||
static int alarm_timer_forward(struct k_itimer *timr, ktime_t now)
|
||||
{
|
||||
struct alarm *alarm = &timr->it.alarm.alarmtimer;
|
||||
|
||||
return (int) alarm_forward(alarm, timr->it_interval, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_remaining - Posix timer callback to retrieve remaining time
|
||||
* @timr: Pointer to the posixtimer data struct
|
||||
* @now: Current time to calculate against
|
||||
*/
|
||||
static ktime_t alarm_timer_remaining(struct k_itimer *timr, ktime_t now)
|
||||
{
|
||||
struct alarm *alarm = &timr->it.alarm.alarmtimer;
|
||||
|
||||
return ktime_sub(now, alarm->node.expires);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_try_to_cancel - Posix timer callback to cancel a timer
|
||||
* @timr: Pointer to the posixtimer data struct
|
||||
*/
|
||||
static int alarm_timer_try_to_cancel(struct k_itimer *timr)
|
||||
{
|
||||
return alarm_try_to_cancel(&timr->it.alarm.alarmtimer);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_arm - Posix timer callback to arm a timer
|
||||
* @timr: Pointer to the posixtimer data struct
|
||||
* @expires: The new expiry time
|
||||
* @absolute: Expiry value is absolute time
|
||||
* @sigev_none: Posix timer does not deliver signals
|
||||
*/
|
||||
static void alarm_timer_arm(struct k_itimer *timr, ktime_t expires,
|
||||
bool absolute, bool sigev_none)
|
||||
{
|
||||
struct alarm *alarm = &timr->it.alarm.alarmtimer;
|
||||
struct alarm_base *base = &alarm_bases[alarm->type];
|
||||
|
||||
if (!absolute)
|
||||
expires = ktime_add_safe(expires, base->gettime());
|
||||
if (sigev_none)
|
||||
alarm->node.expires = expires;
|
||||
else
|
||||
alarm_start(&timr->it.alarm.alarmtimer, expires);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_clock_getres - posix getres interface
|
||||
* @which_clock: clockid
|
||||
@@ -590,97 +665,6 @@ static int alarm_timer_create(struct k_itimer *new_timer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_get - posix timer_get interface
|
||||
* @new_timer: k_itimer pointer
|
||||
* @cur_setting: itimerspec data to fill
|
||||
*
|
||||
* Copies out the current itimerspec data
|
||||
*/
|
||||
static void alarm_timer_get(struct k_itimer *timr,
|
||||
struct itimerspec64 *cur_setting)
|
||||
{
|
||||
ktime_t relative_expiry_time =
|
||||
alarm_expires_remaining(&(timr->it.alarm.alarmtimer));
|
||||
|
||||
if (ktime_to_ns(relative_expiry_time) > 0) {
|
||||
cur_setting->it_value = ktime_to_timespec64(relative_expiry_time);
|
||||
} else {
|
||||
cur_setting->it_value.tv_sec = 0;
|
||||
cur_setting->it_value.tv_nsec = 0;
|
||||
}
|
||||
|
||||
cur_setting->it_interval = ktime_to_timespec64(timr->it.alarm.interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_del - posix timer_del interface
|
||||
* @timr: k_itimer pointer to be deleted
|
||||
*
|
||||
* Cancels any programmed alarms for the given timer.
|
||||
*/
|
||||
static int alarm_timer_del(struct k_itimer *timr)
|
||||
{
|
||||
if (!rtcdev)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0)
|
||||
return TIMER_RETRY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_timer_set - posix timer_set interface
|
||||
* @timr: k_itimer pointer to be deleted
|
||||
* @flags: timer flags
|
||||
* @new_setting: itimerspec to be used
|
||||
* @old_setting: itimerspec being replaced
|
||||
*
|
||||
* Sets the timer to new_setting, and starts the timer.
|
||||
*/
|
||||
static int alarm_timer_set(struct k_itimer *timr, int flags,
|
||||
struct itimerspec64 *new_setting,
|
||||
struct itimerspec64 *old_setting)
|
||||
{
|
||||
ktime_t exp;
|
||||
|
||||
if (!rtcdev)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (flags & ~TIMER_ABSTIME)
|
||||
return -EINVAL;
|
||||
|
||||
if (old_setting)
|
||||
alarm_timer_get(timr, old_setting);
|
||||
|
||||
/* If the timer was already set, cancel it */
|
||||
if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0)
|
||||
return TIMER_RETRY;
|
||||
|
||||
/* start the timer */
|
||||
timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval);
|
||||
|
||||
/*
|
||||
* Rate limit to the tick as a hot fix to prevent DOS. Will be
|
||||
* mopped up later.
|
||||
*/
|
||||
if (timr->it.alarm.interval < TICK_NSEC)
|
||||
timr->it.alarm.interval = TICK_NSEC;
|
||||
|
||||
exp = timespec64_to_ktime(new_setting->it_value);
|
||||
/* Convert (if necessary) to absolute time */
|
||||
if (flags != TIMER_ABSTIME) {
|
||||
ktime_t now;
|
||||
|
||||
now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime();
|
||||
exp = ktime_add_safe(now, exp);
|
||||
}
|
||||
|
||||
alarm_start(&timr->it.alarm.alarmtimer, exp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep
|
||||
* @alarm: ptr to alarm that fired
|
||||
@@ -705,8 +689,10 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
|
||||
*
|
||||
* Sets the alarm timer and sleeps until it is fired or interrupted.
|
||||
*/
|
||||
static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
|
||||
static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
|
||||
enum alarmtimer_type type)
|
||||
{
|
||||
struct restart_block *restart;
|
||||
alarm->data = (void *)current;
|
||||
do {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
@@ -719,36 +705,25 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp)
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
return (alarm->data == NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update_rmtp - Update remaining timespec value
|
||||
* @exp: expiration time
|
||||
* @type: timer type
|
||||
* @rmtp: user pointer to remaining timepsec 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)
|
||||
{
|
||||
struct timespec rmt;
|
||||
ktime_t rem;
|
||||
|
||||
rem = ktime_sub(exp, alarm_bases[type].gettime());
|
||||
|
||||
if (rem <= 0)
|
||||
if (!alarm->data)
|
||||
return 0;
|
||||
rmt = ktime_to_timespec(rem);
|
||||
|
||||
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
|
||||
return -EFAULT;
|
||||
if (freezing(current))
|
||||
alarmtimer_freezerset(absexp, type);
|
||||
restart = ¤t->restart_block;
|
||||
if (restart->nanosleep.type != TT_NONE) {
|
||||
struct timespec rmt;
|
||||
ktime_t rem;
|
||||
|
||||
return 1;
|
||||
rem = ktime_sub(absexp, alarm_bases[type].gettime());
|
||||
|
||||
if (rem <= 0)
|
||||
return 0;
|
||||
rmt = ktime_to_timespec(rem);
|
||||
|
||||
return nanosleep_copyout(restart, &rmt);
|
||||
}
|
||||
return -ERESTART_RESTARTBLOCK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -760,32 +735,12 @@ static int update_rmtp(ktime_t exp, enum alarmtimer_type type,
|
||||
static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
|
||||
{
|
||||
enum alarmtimer_type type = restart->nanosleep.clockid;
|
||||
ktime_t exp;
|
||||
struct timespec __user *rmtp;
|
||||
ktime_t exp = restart->nanosleep.expires;
|
||||
struct alarm alarm;
|
||||
int ret = 0;
|
||||
|
||||
exp = restart->nanosleep.expires;
|
||||
alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
|
||||
|
||||
if (alarmtimer_do_nsleep(&alarm, exp))
|
||||
goto out;
|
||||
|
||||
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:
|
||||
return ret;
|
||||
return alarmtimer_do_nsleep(&alarm, exp, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -798,11 +753,10 @@ out:
|
||||
* Handles clock_nanosleep calls against _ALARM clockids
|
||||
*/
|
||||
static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
||||
struct timespec64 *tsreq,
|
||||
struct timespec __user *rmtp)
|
||||
const struct timespec64 *tsreq)
|
||||
{
|
||||
enum alarmtimer_type type = clock2alarm(which_clock);
|
||||
struct restart_block *restart;
|
||||
struct restart_block *restart = ¤t->restart_block;
|
||||
struct alarm alarm;
|
||||
ktime_t exp;
|
||||
int ret = 0;
|
||||
@@ -825,35 +779,36 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
|
||||
exp = ktime_add(now, exp);
|
||||
}
|
||||
|
||||
if (alarmtimer_do_nsleep(&alarm, exp))
|
||||
goto out;
|
||||
|
||||
if (freezing(current))
|
||||
alarmtimer_freezerset(exp, type);
|
||||
ret = alarmtimer_do_nsleep(&alarm, exp, type);
|
||||
if (ret != -ERESTART_RESTARTBLOCK)
|
||||
return ret;
|
||||
|
||||
/* abs timers don't set remaining time or restart */
|
||||
if (flags == TIMER_ABSTIME) {
|
||||
ret = -ERESTARTNOHAND;
|
||||
goto out;
|
||||
}
|
||||
if (flags == TIMER_ABSTIME)
|
||||
return -ERESTARTNOHAND;
|
||||
|
||||
if (rmtp) {
|
||||
ret = update_rmtp(exp, type, rmtp);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
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:
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct k_clock alarm_clock = {
|
||||
.clock_getres = alarm_clock_getres,
|
||||
.clock_get = alarm_clock_get,
|
||||
.timer_create = alarm_timer_create,
|
||||
.timer_set = common_timer_set,
|
||||
.timer_del = common_timer_del,
|
||||
.timer_get = common_timer_get,
|
||||
.timer_arm = alarm_timer_arm,
|
||||
.timer_rearm = alarm_timer_rearm,
|
||||
.timer_forward = alarm_timer_forward,
|
||||
.timer_remaining = alarm_timer_remaining,
|
||||
.timer_try_to_cancel = alarm_timer_try_to_cancel,
|
||||
.nsleep = alarm_timer_nsleep,
|
||||
};
|
||||
#endif /* CONFIG_POSIX_TIMERS */
|
||||
|
||||
|
||||
/* Suspend hook structures */
|
||||
static const struct dev_pm_ops alarmtimer_pm_ops = {
|
||||
@@ -879,23 +834,9 @@ static int __init alarmtimer_init(void)
|
||||
struct platform_device *pdev;
|
||||
int error = 0;
|
||||
int i;
|
||||
struct k_clock alarm_clock = {
|
||||
.clock_getres = alarm_clock_getres,
|
||||
.clock_get = alarm_clock_get,
|
||||
.timer_create = alarm_timer_create,
|
||||
.timer_set = alarm_timer_set,
|
||||
.timer_del = alarm_timer_del,
|
||||
.timer_get = alarm_timer_get,
|
||||
.nsleep = alarm_timer_nsleep,
|
||||
};
|
||||
|
||||
alarmtimer_rtc_timer_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
|
||||
posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);
|
||||
posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock);
|
||||
}
|
||||
|
||||
/* Initialize alarm bases */
|
||||
alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
|
||||
alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real;
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <linux/sched/debug.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
@@ -1439,8 +1440,29 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
|
||||
|
||||
int nanosleep_copyout(struct restart_block *restart, struct timespec *ts)
|
||||
{
|
||||
switch(restart->nanosleep.type) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
case TT_COMPAT:
|
||||
if (compat_put_timespec(ts, restart->nanosleep.compat_rmtp))
|
||||
return -EFAULT;
|
||||
break;
|
||||
#endif
|
||||
case TT_NATIVE:
|
||||
if (copy_to_user(restart->nanosleep.rmtp, ts, sizeof(struct timespec)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
return -ERESTART_RESTARTBLOCK;
|
||||
}
|
||||
|
||||
static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
|
||||
{
|
||||
struct restart_block *restart;
|
||||
|
||||
hrtimer_init_sleeper(t, current);
|
||||
|
||||
do {
|
||||
@@ -1457,53 +1479,38 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
return t->task == NULL;
|
||||
}
|
||||
|
||||
static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp)
|
||||
{
|
||||
struct timespec rmt;
|
||||
ktime_t rem;
|
||||
|
||||
rem = hrtimer_expires_remaining(timer);
|
||||
if (rem <= 0)
|
||||
if (!t->task)
|
||||
return 0;
|
||||
rmt = ktime_to_timespec(rem);
|
||||
|
||||
if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
|
||||
return -EFAULT;
|
||||
restart = ¤t->restart_block;
|
||||
if (restart->nanosleep.type != TT_NONE) {
|
||||
ktime_t rem = hrtimer_expires_remaining(&t->timer);
|
||||
struct timespec rmt;
|
||||
|
||||
return 1;
|
||||
if (rem <= 0)
|
||||
return 0;
|
||||
rmt = ktime_to_timespec(rem);
|
||||
|
||||
return nanosleep_copyout(restart, &rmt);
|
||||
}
|
||||
return -ERESTART_RESTARTBLOCK;
|
||||
}
|
||||
|
||||
long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
||||
static long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
||||
{
|
||||
struct hrtimer_sleeper t;
|
||||
struct timespec __user *rmtp;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid,
|
||||
HRTIMER_MODE_ABS);
|
||||
hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
|
||||
|
||||
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
|
||||
goto out;
|
||||
|
||||
rmtp = restart->nanosleep.rmtp;
|
||||
if (rmtp) {
|
||||
ret = update_rmtp(&t.timer, rmtp);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The other values in restart are already filled in */
|
||||
ret = -ERESTART_RESTARTBLOCK;
|
||||
out:
|
||||
ret = do_nanosleep(&t, HRTIMER_MODE_ABS);
|
||||
destroy_hrtimer_on_stack(&t.timer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
|
||||
long hrtimer_nanosleep(const struct timespec64 *rqtp,
|
||||
const enum hrtimer_mode mode, const clockid_t clockid)
|
||||
{
|
||||
struct restart_block *restart;
|
||||
@@ -1517,7 +1524,8 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
|
||||
|
||||
hrtimer_init_on_stack(&t.timer, clockid, mode);
|
||||
hrtimer_set_expires_range_ns(&t.timer, timespec64_to_ktime(*rqtp), slack);
|
||||
if (do_nanosleep(&t, mode))
|
||||
ret = do_nanosleep(&t, mode);
|
||||
if (ret != -ERESTART_RESTARTBLOCK)
|
||||
goto out;
|
||||
|
||||
/* Absolute timers do not update the rmtp value and restart: */
|
||||
@@ -1526,19 +1534,10 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rmtp) {
|
||||
ret = update_rmtp(&t.timer, rmtp);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
out:
|
||||
destroy_hrtimer_on_stack(&t.timer);
|
||||
return ret;
|
||||
@@ -1557,9 +1556,32 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
|
||||
if (!timespec64_valid(&tu64))
|
||||
return -EINVAL;
|
||||
|
||||
return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
||||
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
|
||||
current->restart_block.nanosleep.rmtp = rmtp;
|
||||
return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
|
||||
struct compat_timespec __user *, rmtp)
|
||||
{
|
||||
struct timespec64 tu64;
|
||||
struct timespec tu;
|
||||
|
||||
if (compat_get_timespec(&tu, rqtp))
|
||||
return -EFAULT;
|
||||
|
||||
tu64 = timespec_to_timespec64(tu);
|
||||
if (!timespec64_valid(&tu64))
|
||||
return -EINVAL;
|
||||
|
||||
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
|
||||
current->restart_block.nanosleep.compat_rmtp = rmtp;
|
||||
return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions related to boot-time initialization:
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <trace/events/timer.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
@@ -116,6 +117,19 @@ SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
|
||||
struct compat_itimerval __user *, it)
|
||||
{
|
||||
struct itimerval kit;
|
||||
int error = do_getitimer(which, &kit);
|
||||
|
||||
if (!error && put_compat_itimerval(it, &kit))
|
||||
error = -EFAULT;
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The timer is automagically restarted, when interval != 0
|
||||
@@ -138,8 +152,12 @@ static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
||||
u64 oval, nval, ointerval, ninterval;
|
||||
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
||||
|
||||
nval = timeval_to_ns(&value->it_value);
|
||||
ninterval = timeval_to_ns(&value->it_interval);
|
||||
/*
|
||||
* Use the to_ktime conversion because that clamps the maximum
|
||||
* value to KTIME_MAX and avoid multiplication overflows.
|
||||
*/
|
||||
nval = ktime_to_ns(timeval_to_ktime(value->it_value));
|
||||
ninterval = ktime_to_ns(timeval_to_ktime(value->it_interval));
|
||||
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
|
||||
@@ -294,3 +312,27 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
|
||||
struct compat_itimerval __user *, in,
|
||||
struct compat_itimerval __user *, out)
|
||||
{
|
||||
struct itimerval kin, kout;
|
||||
int error;
|
||||
|
||||
if (in) {
|
||||
if (get_compat_itimerval(&kin, in))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
memset(&kin, 0, sizeof(kin));
|
||||
}
|
||||
|
||||
error = do_setitimer(which, &kin, out ? &kout : NULL);
|
||||
if (error || !out)
|
||||
return error;
|
||||
if (put_compat_itimerval(out, &kout))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "posix-timers.h"
|
||||
|
||||
static void delete_clock(struct kref *kref);
|
||||
|
||||
/*
|
||||
@@ -82,38 +84,6 @@ static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int posix_clock_fasync(int fd, struct file *fp, int on)
|
||||
{
|
||||
struct posix_clock *clk = get_posix_clock(fp);
|
||||
int err = 0;
|
||||
|
||||
if (!clk)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->ops.fasync)
|
||||
err = clk->ops.fasync(clk, fd, fp, on);
|
||||
|
||||
put_posix_clock(clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct posix_clock *clk = get_posix_clock(fp);
|
||||
int err = -ENODEV;
|
||||
|
||||
if (!clk)
|
||||
return -ENODEV;
|
||||
|
||||
if (clk->ops.mmap)
|
||||
err = clk->ops.mmap(clk, vma);
|
||||
|
||||
put_posix_clock(clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static long posix_clock_ioctl(struct file *fp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -199,8 +169,6 @@ static const struct file_operations posix_clock_file_operations = {
|
||||
.unlocked_ioctl = posix_clock_ioctl,
|
||||
.open = posix_clock_open,
|
||||
.release = posix_clock_release,
|
||||
.fasync = posix_clock_fasync,
|
||||
.mmap = posix_clock_mmap,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = posix_clock_compat_ioctl,
|
||||
#endif
|
||||
@@ -359,88 +327,9 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pc_timer_create(struct k_itimer *kit)
|
||||
{
|
||||
clockid_t id = kit->it_clock;
|
||||
struct posix_clock_desc cd;
|
||||
int err;
|
||||
|
||||
err = get_clock_desc(id, &cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cd.clk->ops.timer_create)
|
||||
err = cd.clk->ops.timer_create(cd.clk, kit);
|
||||
else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
put_clock_desc(&cd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pc_timer_delete(struct k_itimer *kit)
|
||||
{
|
||||
clockid_t id = kit->it_clock;
|
||||
struct posix_clock_desc cd;
|
||||
int err;
|
||||
|
||||
err = get_clock_desc(id, &cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cd.clk->ops.timer_delete)
|
||||
err = cd.clk->ops.timer_delete(cd.clk, kit);
|
||||
else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
put_clock_desc(&cd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec64 *ts)
|
||||
{
|
||||
clockid_t id = kit->it_clock;
|
||||
struct posix_clock_desc cd;
|
||||
|
||||
if (get_clock_desc(id, &cd))
|
||||
return;
|
||||
|
||||
if (cd.clk->ops.timer_gettime)
|
||||
cd.clk->ops.timer_gettime(cd.clk, kit, ts);
|
||||
|
||||
put_clock_desc(&cd);
|
||||
}
|
||||
|
||||
static int pc_timer_settime(struct k_itimer *kit, int flags,
|
||||
struct itimerspec64 *ts, struct itimerspec64 *old)
|
||||
{
|
||||
clockid_t id = kit->it_clock;
|
||||
struct posix_clock_desc cd;
|
||||
int err;
|
||||
|
||||
err = get_clock_desc(id, &cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (cd.clk->ops.timer_settime)
|
||||
err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old);
|
||||
else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
put_clock_desc(&cd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct k_clock clock_posix_dynamic = {
|
||||
const struct k_clock clock_posix_dynamic = {
|
||||
.clock_getres = pc_clock_getres,
|
||||
.clock_set = pc_clock_settime,
|
||||
.clock_get = pc_clock_gettime,
|
||||
.clock_adj = pc_clock_adjtime,
|
||||
.timer_create = pc_timer_create,
|
||||
.timer_set = pc_timer_settime,
|
||||
.timer_del = pc_timer_delete,
|
||||
.timer_get = pc_timer_gettime,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
#include <trace/events/timer.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "posix-timers.h"
|
||||
|
||||
static void posix_cpu_timer_rearm(struct k_itimer *timer);
|
||||
|
||||
/*
|
||||
* Called after updating RLIMIT_CPU to run cpu timer and update
|
||||
@@ -322,6 +327,8 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
|
||||
if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
new_timer->kclock = &clock_posix_cpu;
|
||||
|
||||
INIT_LIST_HEAD(&new_timer->it.cpu.entry);
|
||||
|
||||
rcu_read_lock();
|
||||
@@ -524,7 +531,8 @@ static void cpu_timer_fire(struct k_itimer *timer)
|
||||
* reload the timer. But we need to keep it
|
||||
* ticking in case the signal is deliverable next time.
|
||||
*/
|
||||
posix_cpu_timer_schedule(timer);
|
||||
posix_cpu_timer_rearm(timer);
|
||||
++timer->it_requeue_pending;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,7 +580,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
|
||||
|
||||
WARN_ON_ONCE(p == NULL);
|
||||
|
||||
new_expires = timespec64_to_ns(&new->it_value);
|
||||
/*
|
||||
* Use the to_ktime conversion because that clamps the maximum
|
||||
* value to KTIME_MAX and avoid multiplication overflows.
|
||||
*/
|
||||
new_expires = ktime_to_ns(timespec64_to_ktime(new->it_value));
|
||||
|
||||
/*
|
||||
* Protect against sighand release/switch in exit/exec and p->cpu_timers
|
||||
@@ -712,10 +724,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
|
||||
*/
|
||||
itp->it_interval = ns_to_timespec64(timer->it.cpu.incr);
|
||||
|
||||
if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */
|
||||
itp->it_value.tv_sec = itp->it_value.tv_nsec = 0;
|
||||
if (!timer->it.cpu.expires)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample the clock to take the difference with the expiry time.
|
||||
@@ -739,7 +749,6 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
|
||||
* Call the timer disarmed, nothing else to do.
|
||||
*/
|
||||
timer->it.cpu.expires = 0;
|
||||
itp->it_value = ns_to_timespec64(timer->it.cpu.expires);
|
||||
return;
|
||||
} else {
|
||||
cpu_timer_sample_group(timer->it_clock, p, &now);
|
||||
@@ -976,10 +985,10 @@ static void check_process_timers(struct task_struct *tsk,
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from the signal code (via do_schedule_next_timer)
|
||||
* This is called from the signal code (via posixtimer_rearm)
|
||||
* when the last timer signal was delivered and we have to reload the timer.
|
||||
*/
|
||||
void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||
static void posix_cpu_timer_rearm(struct k_itimer *timer)
|
||||
{
|
||||
struct sighand_struct *sighand;
|
||||
unsigned long flags;
|
||||
@@ -995,12 +1004,12 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||
cpu_clock_sample(timer->it_clock, p, &now);
|
||||
bump_cpu_timer(timer, now);
|
||||
if (unlikely(p->exit_state))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/* Protect timer list r/w in arm_timer() */
|
||||
sighand = lock_task_sighand(p, &flags);
|
||||
if (!sighand)
|
||||
goto out;
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* Protect arm_timer() and timer sampling in case of call to
|
||||
@@ -1013,11 +1022,10 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||
* We can't even collect a sample any more.
|
||||
*/
|
||||
timer->it.cpu.expires = 0;
|
||||
goto out;
|
||||
return;
|
||||
} else if (unlikely(p->exit_state) && thread_group_empty(p)) {
|
||||
unlock_task_sighand(p, &flags);
|
||||
/* Optimizations: if the process is dying, no need to rearm */
|
||||
goto out;
|
||||
/* If the process is dying, no need to rearm */
|
||||
goto unlock;
|
||||
}
|
||||
cpu_timer_sample_group(timer->it_clock, p, &now);
|
||||
bump_cpu_timer(timer, now);
|
||||
@@ -1029,12 +1037,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
|
||||
*/
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
arm_timer(timer);
|
||||
unlock:
|
||||
unlock_task_sighand(p, &flags);
|
||||
|
||||
out:
|
||||
timer->it_overrun_last = timer->it_overrun;
|
||||
timer->it_overrun = -1;
|
||||
++timer->it_requeue_pending;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1227,9 +1231,11 @@ 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,
|
||||
struct timespec64 *rqtp, struct itimerspec64 *it)
|
||||
const struct timespec64 *rqtp)
|
||||
{
|
||||
struct itimerspec64 it;
|
||||
struct k_itimer timer;
|
||||
u64 expires;
|
||||
int error;
|
||||
|
||||
/*
|
||||
@@ -1243,12 +1249,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||
timer.it_process = current;
|
||||
if (!error) {
|
||||
static struct itimerspec64 zero_it;
|
||||
struct restart_block *restart;
|
||||
|
||||
memset(it, 0, sizeof *it);
|
||||
it->it_value = *rqtp;
|
||||
memset(&it, 0, sizeof(it));
|
||||
it.it_value = *rqtp;
|
||||
|
||||
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) {
|
||||
spin_unlock_irq(&timer.it_lock);
|
||||
return error;
|
||||
@@ -1277,8 +1284,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||
/*
|
||||
* We were interrupted by a signal.
|
||||
*/
|
||||
*rqtp = ns_to_timespec64(timer.it.cpu.expires);
|
||||
error = posix_cpu_timer_set(&timer, 0, &zero_it, it);
|
||||
expires = timer.it.cpu.expires;
|
||||
error = posix_cpu_timer_set(&timer, 0, &zero_it, &it);
|
||||
if (!error) {
|
||||
/*
|
||||
* Timer is now unarmed, deletion can not fail.
|
||||
@@ -1298,7 +1305,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||
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.
|
||||
*/
|
||||
@@ -1306,6 +1313,17 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||
}
|
||||
|
||||
error = -ERESTART_RESTARTBLOCK;
|
||||
/*
|
||||
* Report back to the user the time still remaining.
|
||||
*/
|
||||
restart = ¤t->restart_block;
|
||||
restart->nanosleep.expires = expires;
|
||||
if (restart->nanosleep.type != TT_NONE) {
|
||||
struct timespec ts;
|
||||
|
||||
ts = timespec64_to_timespec(it.it_value);
|
||||
error = nanosleep_copyout(restart, &ts);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -1314,11 +1332,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
|
||||
static long posix_cpu_nsleep_restart(struct restart_block *restart_block);
|
||||
|
||||
static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
|
||||
struct timespec64 *rqtp, struct timespec __user *rmtp)
|
||||
const struct timespec64 *rqtp)
|
||||
{
|
||||
struct restart_block *restart_block = ¤t->restart_block;
|
||||
struct itimerspec64 it;
|
||||
struct timespec ts;
|
||||
int error;
|
||||
|
||||
/*
|
||||
@@ -1329,23 +1345,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
|
||||
CPUCLOCK_PID(which_clock) == task_pid_vnr(current)))
|
||||
return -EINVAL;
|
||||
|
||||
error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
|
||||
error = do_cpu_nanosleep(which_clock, flags, rqtp);
|
||||
|
||||
if (error == -ERESTART_RESTARTBLOCK) {
|
||||
|
||||
if (flags & TIMER_ABSTIME)
|
||||
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->nanosleep.clockid = which_clock;
|
||||
restart_block->nanosleep.rmtp = rmtp;
|
||||
restart_block->nanosleep.expires = timespec64_to_ns(rqtp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -1353,28 +1361,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
|
||||
static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
restart_block->nanosleep.expires = timespec64_to_ns(&t);
|
||||
}
|
||||
return error;
|
||||
|
||||
return do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t);
|
||||
}
|
||||
|
||||
#define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
|
||||
@@ -1396,14 +1387,9 @@ static int process_cpu_timer_create(struct k_itimer *timer)
|
||||
return posix_cpu_timer_create(timer);
|
||||
}
|
||||
static int process_cpu_nsleep(const clockid_t which_clock, int flags,
|
||||
struct timespec64 *rqtp,
|
||||
struct timespec __user *rmtp)
|
||||
const struct timespec64 *rqtp)
|
||||
{
|
||||
return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp);
|
||||
}
|
||||
static long process_cpu_nsleep_restart(struct restart_block *restart_block)
|
||||
{
|
||||
return -EINVAL;
|
||||
return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
|
||||
}
|
||||
static int thread_cpu_clock_getres(const clockid_t which_clock,
|
||||
struct timespec64 *tp)
|
||||
@@ -1421,36 +1407,27 @@ static int thread_cpu_timer_create(struct k_itimer *timer)
|
||||
return posix_cpu_timer_create(timer);
|
||||
}
|
||||
|
||||
struct k_clock clock_posix_cpu = {
|
||||
const struct k_clock clock_posix_cpu = {
|
||||
.clock_getres = posix_cpu_clock_getres,
|
||||
.clock_set = posix_cpu_clock_set,
|
||||
.clock_get = posix_cpu_clock_get,
|
||||
.timer_create = posix_cpu_timer_create,
|
||||
.nsleep = posix_cpu_nsleep,
|
||||
.nsleep_restart = posix_cpu_nsleep_restart,
|
||||
.timer_set = posix_cpu_timer_set,
|
||||
.timer_del = posix_cpu_timer_del,
|
||||
.timer_get = posix_cpu_timer_get,
|
||||
.timer_rearm = posix_cpu_timer_rearm,
|
||||
};
|
||||
|
||||
static __init int init_posix_cpu_timers(void)
|
||||
{
|
||||
struct k_clock process = {
|
||||
.clock_getres = process_cpu_clock_getres,
|
||||
.clock_get = process_cpu_clock_get,
|
||||
.timer_create = process_cpu_timer_create,
|
||||
.nsleep = process_cpu_nsleep,
|
||||
.nsleep_restart = process_cpu_nsleep_restart,
|
||||
};
|
||||
struct k_clock thread = {
|
||||
.clock_getres = thread_cpu_clock_getres,
|
||||
.clock_get = thread_cpu_clock_get,
|
||||
.timer_create = thread_cpu_timer_create,
|
||||
};
|
||||
const struct k_clock clock_process = {
|
||||
.clock_getres = process_cpu_clock_getres,
|
||||
.clock_get = process_cpu_clock_get,
|
||||
.timer_create = process_cpu_timer_create,
|
||||
.nsleep = process_cpu_nsleep,
|
||||
};
|
||||
|
||||
posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
|
||||
posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(init_posix_cpu_timers);
|
||||
const struct k_clock clock_thread = {
|
||||
.clock_getres = thread_cpu_clock_getres,
|
||||
.clock_get = thread_cpu_clock_get,
|
||||
.timer_create = thread_cpu_timer_create,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
asmlinkage long sys_ni_posix_timers(void)
|
||||
{
|
||||
@@ -27,6 +28,7 @@ asmlinkage long sys_ni_posix_timers(void)
|
||||
}
|
||||
|
||||
#define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers)
|
||||
#define COMPAT_SYS_NI(name) SYSCALL_ALIAS(compat_sys_##name, sys_ni_posix_timers)
|
||||
|
||||
SYS_NI(timer_create);
|
||||
SYS_NI(timer_gettime);
|
||||
@@ -39,6 +41,12 @@ SYS_NI(setitimer);
|
||||
#ifdef __ARCH_WANT_SYS_ALARM
|
||||
SYS_NI(alarm);
|
||||
#endif
|
||||
COMPAT_SYS_NI(timer_create);
|
||||
COMPAT_SYS_NI(clock_adjtime);
|
||||
COMPAT_SYS_NI(timer_settime);
|
||||
COMPAT_SYS_NI(timer_gettime);
|
||||
COMPAT_SYS_NI(getitimer);
|
||||
COMPAT_SYS_NI(setitimer);
|
||||
|
||||
/*
|
||||
* We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
|
||||
@@ -110,22 +118,106 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_BOOTTIME:
|
||||
if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
|
||||
return -EFAULT;
|
||||
t64 = timespec_to_timespec64(t);
|
||||
if (!timespec64_valid(&t64))
|
||||
return -EINVAL;
|
||||
if (flags & TIMER_ABSTIME)
|
||||
rmtp = NULL;
|
||||
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
|
||||
current->restart_block.nanosleep.rmtp = rmtp;
|
||||
return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
|
||||
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
|
||||
which_clock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
struct timespec64 new_tp64;
|
||||
struct timespec new_tp;
|
||||
|
||||
if (which_clock != CLOCK_REALTIME)
|
||||
return -EINVAL;
|
||||
if (compat_get_timespec(&new_tp, tp))
|
||||
return -EFAULT;
|
||||
|
||||
new_tp64 = timespec_to_timespec64(new_tp);
|
||||
return do_sys_settimeofday64(&new_tp64, NULL);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
|
||||
struct compat_timespec __user *,tp)
|
||||
{
|
||||
struct timespec64 kernel_tp64;
|
||||
struct timespec kernel_tp;
|
||||
|
||||
switch (which_clock) {
|
||||
case CLOCK_REALTIME: ktime_get_real_ts64(&kernel_tp64); break;
|
||||
case CLOCK_MONOTONIC: ktime_get_ts64(&kernel_tp64); break;
|
||||
case CLOCK_BOOTTIME: get_monotonic_boottime64(&kernel_tp64); break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
|
||||
kernel_tp = timespec64_to_timespec(kernel_tp64);
|
||||
if (compat_put_timespec(&kernel_tp, tp))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
|
||||
struct compat_timespec __user *, tp)
|
||||
{
|
||||
struct timespec rtn_tp = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = hrtimer_resolution,
|
||||
};
|
||||
|
||||
switch (which_clock) {
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_BOOTTIME:
|
||||
if (compat_put_timespec(&rtn_tp, tp))
|
||||
return -EFAULT;
|
||||
t64 = timespec_to_timespec64(t);
|
||||
if (!timespec64_valid(&t64))
|
||||
return -EINVAL;
|
||||
return hrtimer_nanosleep(&t64, rmtp, flags & TIMER_ABSTIME ?
|
||||
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
|
||||
which_clock);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
long clock_nanosleep_restart(struct restart_block *restart_block)
|
||||
COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
|
||||
struct compat_timespec __user *, rqtp,
|
||||
struct compat_timespec __user *, rmtp)
|
||||
{
|
||||
return hrtimer_nanosleep_restart(restart_block);
|
||||
struct timespec64 t64;
|
||||
struct timespec t;
|
||||
|
||||
switch (which_clock) {
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_BOOTTIME:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (compat_get_timespec(&t, rqtp))
|
||||
return -EFAULT;
|
||||
t64 = timespec_to_timespec64(t);
|
||||
if (!timespec64_valid(&t64))
|
||||
return -EINVAL;
|
||||
if (flags & TIMER_ABSTIME)
|
||||
rmtp = NULL;
|
||||
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
|
||||
current->restart_block.nanosleep.compat_rmtp = rmtp;
|
||||
return hrtimer_nanosleep(&t64, flags & TIMER_ABSTIME ?
|
||||
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
|
||||
which_clock);
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
40
kernel/time/posix-timers.h
Normal file
40
kernel/time/posix-timers.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#define TIMER_RETRY 1
|
||||
|
||||
struct k_clock {
|
||||
int (*clock_getres)(const clockid_t which_clock,
|
||||
struct timespec64 *tp);
|
||||
int (*clock_set)(const clockid_t which_clock,
|
||||
const struct timespec64 *tp);
|
||||
int (*clock_get)(const clockid_t which_clock,
|
||||
struct timespec64 *tp);
|
||||
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,
|
||||
const struct timespec64 *);
|
||||
int (*timer_set)(struct k_itimer *timr, int flags,
|
||||
struct itimerspec64 *new_setting,
|
||||
struct itimerspec64 *old_setting);
|
||||
int (*timer_del)(struct k_itimer *timr);
|
||||
void (*timer_get)(struct k_itimer *timr,
|
||||
struct itimerspec64 *cur_setting);
|
||||
void (*timer_rearm)(struct k_itimer *timr);
|
||||
int (*timer_forward)(struct k_itimer *timr, ktime_t now);
|
||||
ktime_t (*timer_remaining)(struct k_itimer *timr, ktime_t now);
|
||||
int (*timer_try_to_cancel)(struct k_itimer *timr);
|
||||
void (*timer_arm)(struct k_itimer *timr, ktime_t expires,
|
||||
bool absolute, bool sigev_none);
|
||||
};
|
||||
|
||||
extern const struct k_clock clock_posix_cpu;
|
||||
extern const struct k_clock clock_posix_dynamic;
|
||||
extern const struct k_clock clock_process;
|
||||
extern const struct k_clock clock_thread;
|
||||
extern const struct k_clock alarm_clock;
|
||||
|
||||
int posix_timer_event(struct k_itimer *timr, int si_private);
|
||||
|
||||
void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting);
|
||||
int common_timer_set(struct k_itimer *timr, int flags,
|
||||
struct itimerspec64 *new_setting,
|
||||
struct itimerspec64 *old_setting);
|
||||
int common_timer_del(struct k_itimer *timer);
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/compat.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include <generated/timeconst.h>
|
||||
@@ -99,6 +100,47 @@ SYSCALL_DEFINE1(stime, time_t __user *, tptr)
|
||||
|
||||
#endif /* __ARCH_WANT_SYS_TIME */
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#ifdef __ARCH_WANT_COMPAT_SYS_TIME
|
||||
|
||||
/* compat_time_t is a 32 bit "long" and needs to get converted. */
|
||||
COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
|
||||
{
|
||||
struct timeval tv;
|
||||
compat_time_t i;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
i = tv.tv_sec;
|
||||
|
||||
if (tloc) {
|
||||
if (put_user(i,tloc))
|
||||
return -EFAULT;
|
||||
}
|
||||
force_successful_syscall_return();
|
||||
return i;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
|
||||
{
|
||||
struct timespec tv;
|
||||
int err;
|
||||
|
||||
if (get_user(tv.tv_sec, tptr))
|
||||
return -EFAULT;
|
||||
|
||||
tv.tv_nsec = 0;
|
||||
|
||||
err = security_settime(&tv, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do_settimeofday(&tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
|
||||
#endif
|
||||
|
||||
SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
@@ -215,6 +257,47 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv,
|
||||
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
if (tv) {
|
||||
struct timeval ktv;
|
||||
|
||||
do_gettimeofday(&ktv);
|
||||
if (compat_put_timeval(&ktv, tv))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (tz) {
|
||||
if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
struct timespec64 new_ts;
|
||||
struct timeval user_tv;
|
||||
struct timezone new_tz;
|
||||
|
||||
if (tv) {
|
||||
if (compat_get_timeval(&user_tv, tv))
|
||||
return -EFAULT;
|
||||
new_ts.tv_sec = user_tv.tv_sec;
|
||||
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
|
||||
}
|
||||
if (tz) {
|
||||
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
|
||||
{
|
||||
struct timex txc; /* Local copy of parameter */
|
||||
@@ -224,12 +307,33 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
|
||||
* structure. But bear in mind that the structures
|
||||
* may change
|
||||
*/
|
||||
if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
|
||||
if (copy_from_user(&txc, txc_p, sizeof(struct timex)))
|
||||
return -EFAULT;
|
||||
ret = do_adjtimex(&txc);
|
||||
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)
|
||||
{
|
||||
struct timex txc;
|
||||
int err, ret;
|
||||
|
||||
err = compat_get_timex(&txc, utp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ret = do_adjtimex(&txc);
|
||||
|
||||
err = compat_put_timex(utp, &txc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert jiffies to milliseconds and back.
|
||||
*
|
||||
|
||||
@@ -72,6 +72,10 @@ static inline void tk_normalize_xtime(struct timekeeper *tk)
|
||||
tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
|
||||
tk->xtime_sec++;
|
||||
}
|
||||
while (tk->tkr_raw.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_raw.shift)) {
|
||||
tk->tkr_raw.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
|
||||
tk->raw_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct timespec64 tk_xtime(struct timekeeper *tk)
|
||||
@@ -285,12 +289,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
|
||||
/* if changing clocks, convert xtime_nsec shift units */
|
||||
if (old_clock) {
|
||||
int shift_change = clock->shift - old_clock->shift;
|
||||
if (shift_change < 0)
|
||||
if (shift_change < 0) {
|
||||
tk->tkr_mono.xtime_nsec >>= -shift_change;
|
||||
else
|
||||
tk->tkr_raw.xtime_nsec >>= -shift_change;
|
||||
} else {
|
||||
tk->tkr_mono.xtime_nsec <<= shift_change;
|
||||
tk->tkr_raw.xtime_nsec <<= shift_change;
|
||||
}
|
||||
}
|
||||
tk->tkr_raw.xtime_nsec = 0;
|
||||
|
||||
tk->tkr_mono.shift = clock->shift;
|
||||
tk->tkr_raw.shift = clock->shift;
|
||||
@@ -510,6 +516,7 @@ static void halt_fast_timekeeper(struct timekeeper *tk)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD
|
||||
#warning Please contact your maintainers, as GENERIC_TIME_VSYSCALL_OLD compatibity will disappear soon.
|
||||
|
||||
static inline void update_vsyscall(struct timekeeper *tk)
|
||||
{
|
||||
@@ -619,9 +626,6 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
|
||||
nsec = (u32) tk->wall_to_monotonic.tv_nsec;
|
||||
tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
|
||||
|
||||
/* Update the monotonic raw base */
|
||||
tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time);
|
||||
|
||||
/*
|
||||
* The sum of the nanoseconds portions of xtime and
|
||||
* wall_to_monotonic can be greater/equal one second. Take
|
||||
@@ -631,6 +635,11 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
|
||||
if (nsec >= NSEC_PER_SEC)
|
||||
seconds++;
|
||||
tk->ktime_sec = seconds;
|
||||
|
||||
/* Update the monotonic raw base */
|
||||
seconds = tk->raw_sec;
|
||||
nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift);
|
||||
tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
|
||||
}
|
||||
|
||||
/* must hold timekeeper_lock */
|
||||
@@ -672,7 +681,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
|
||||
static void timekeeping_forward_now(struct timekeeper *tk)
|
||||
{
|
||||
u64 cycle_now, delta;
|
||||
u64 nsec;
|
||||
|
||||
cycle_now = tk_clock_read(&tk->tkr_mono);
|
||||
delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
|
||||
@@ -684,10 +692,13 @@ static void timekeeping_forward_now(struct timekeeper *tk)
|
||||
/* If arch requires, add in get_arch_timeoffset() */
|
||||
tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift;
|
||||
|
||||
tk_normalize_xtime(tk);
|
||||
|
||||
nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift);
|
||||
timespec64_add_ns(&tk->raw_time, nsec);
|
||||
tk->tkr_raw.xtime_nsec += delta * tk->tkr_raw.mult;
|
||||
|
||||
/* If arch requires, add in get_arch_timeoffset() */
|
||||
tk->tkr_raw.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_raw.shift;
|
||||
|
||||
tk_normalize_xtime(tk);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1373,19 +1384,18 @@ int timekeeping_notify(struct clocksource *clock)
|
||||
void getrawmonotonic64(struct timespec64 *ts)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
struct timespec64 ts64;
|
||||
unsigned long seq;
|
||||
u64 nsecs;
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
ts->tv_sec = tk->raw_sec;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_raw);
|
||||
ts64 = tk->raw_time;
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
timespec64_add_ns(&ts64, nsecs);
|
||||
*ts = ts64;
|
||||
ts->tv_nsec = 0;
|
||||
timespec64_add_ns(ts, nsecs);
|
||||
}
|
||||
EXPORT_SYMBOL(getrawmonotonic64);
|
||||
|
||||
@@ -1509,8 +1519,7 @@ void __init timekeeping_init(void)
|
||||
tk_setup_internals(tk, clock);
|
||||
|
||||
tk_set_xtime(tk, &now);
|
||||
tk->raw_time.tv_sec = 0;
|
||||
tk->raw_time.tv_nsec = 0;
|
||||
tk->raw_sec = 0;
|
||||
if (boot.tv_sec == 0 && boot.tv_nsec == 0)
|
||||
boot = tk_xtime(tk);
|
||||
|
||||
@@ -2011,15 +2020,12 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset,
|
||||
*clock_set |= accumulate_nsecs_to_secs(tk);
|
||||
|
||||
/* Accumulate raw time */
|
||||
tk->tkr_raw.xtime_nsec += (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
|
||||
tk->tkr_raw.xtime_nsec += tk->raw_interval << shift;
|
||||
snsec_per_sec = (u64)NSEC_PER_SEC << tk->tkr_raw.shift;
|
||||
while (tk->tkr_raw.xtime_nsec >= snsec_per_sec) {
|
||||
tk->tkr_raw.xtime_nsec -= snsec_per_sec;
|
||||
tk->raw_time.tv_sec++;
|
||||
tk->raw_sec++;
|
||||
}
|
||||
tk->raw_time.tv_nsec = tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift;
|
||||
tk->tkr_raw.xtime_nsec -= (u64)tk->raw_time.tv_nsec << tk->tkr_raw.shift;
|
||||
|
||||
/* Accumulate error between NTP and clock interval */
|
||||
tk->ntp_error += tk->ntp_tick << shift;
|
||||
|
||||
@@ -195,7 +195,7 @@ EXPORT_SYMBOL(jiffies_64);
|
||||
#endif
|
||||
|
||||
struct timer_base {
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
struct timer_list *running_timer;
|
||||
unsigned long clk;
|
||||
unsigned long next_expiry;
|
||||
@@ -913,10 +913,10 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
|
||||
|
||||
if (!(tf & TIMER_MIGRATING)) {
|
||||
base = get_timer_base(tf);
|
||||
spin_lock_irqsave(&base->lock, *flags);
|
||||
raw_spin_lock_irqsave(&base->lock, *flags);
|
||||
if (timer->flags == tf)
|
||||
return base;
|
||||
spin_unlock_irqrestore(&base->lock, *flags);
|
||||
raw_spin_unlock_irqrestore(&base->lock, *flags);
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
@@ -986,9 +986,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
||||
/* See the comment in lock_timer_base() */
|
||||
timer->flags |= TIMER_MIGRATING;
|
||||
|
||||
spin_unlock(&base->lock);
|
||||
raw_spin_unlock(&base->lock);
|
||||
base = new_base;
|
||||
spin_lock(&base->lock);
|
||||
raw_spin_lock(&base->lock);
|
||||
WRITE_ONCE(timer->flags,
|
||||
(timer->flags & ~TIMER_BASEMASK) | base->cpu);
|
||||
}
|
||||
@@ -1013,7 +1013,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&base->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&base->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1106,16 +1106,16 @@ void add_timer_on(struct timer_list *timer, int cpu)
|
||||
if (base != new_base) {
|
||||
timer->flags |= TIMER_MIGRATING;
|
||||
|
||||
spin_unlock(&base->lock);
|
||||
raw_spin_unlock(&base->lock);
|
||||
base = new_base;
|
||||
spin_lock(&base->lock);
|
||||
raw_spin_lock(&base->lock);
|
||||
WRITE_ONCE(timer->flags,
|
||||
(timer->flags & ~TIMER_BASEMASK) | cpu);
|
||||
}
|
||||
|
||||
debug_activate(timer, timer->expires);
|
||||
internal_add_timer(base, timer);
|
||||
spin_unlock_irqrestore(&base->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&base->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(add_timer_on);
|
||||
|
||||
@@ -1141,7 +1141,7 @@ int del_timer(struct timer_list *timer)
|
||||
if (timer_pending(timer)) {
|
||||
base = lock_timer_base(timer, &flags);
|
||||
ret = detach_if_pending(timer, base, true);
|
||||
spin_unlock_irqrestore(&base->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&base->lock, flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1150,7 +1150,7 @@ EXPORT_SYMBOL(del_timer);
|
||||
|
||||
/**
|
||||
* try_to_del_timer_sync - Try to deactivate a timer
|
||||
* @timer: timer do del
|
||||
* @timer: timer to delete
|
||||
*
|
||||
* This function tries to deactivate a timer. Upon successful (ret >= 0)
|
||||
* exit the timer is not queued and the handler is not running on any CPU.
|
||||
@@ -1168,7 +1168,7 @@ int try_to_del_timer_sync(struct timer_list *timer)
|
||||
if (base->running_timer != timer)
|
||||
ret = detach_if_pending(timer, base, true);
|
||||
|
||||
spin_unlock_irqrestore(&base->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&base->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1299,13 +1299,13 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
|
||||
data = timer->data;
|
||||
|
||||
if (timer->flags & TIMER_IRQSAFE) {
|
||||
spin_unlock(&base->lock);
|
||||
raw_spin_unlock(&base->lock);
|
||||
call_timer_fn(timer, fn, data);
|
||||
spin_lock(&base->lock);
|
||||
raw_spin_lock(&base->lock);
|
||||
} else {
|
||||
spin_unlock_irq(&base->lock);
|
||||
raw_spin_unlock_irq(&base->lock);
|
||||
call_timer_fn(timer, fn, data);
|
||||
spin_lock_irq(&base->lock);
|
||||
raw_spin_lock_irq(&base->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1474,7 +1474,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
||||
if (cpu_is_offline(smp_processor_id()))
|
||||
return expires;
|
||||
|
||||
spin_lock(&base->lock);
|
||||
raw_spin_lock(&base->lock);
|
||||
nextevt = __next_timer_interrupt(base);
|
||||
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
|
||||
base->next_expiry = nextevt;
|
||||
@@ -1502,7 +1502,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
||||
if ((expires - basem) > TICK_NSEC)
|
||||
base->is_idle = true;
|
||||
}
|
||||
spin_unlock(&base->lock);
|
||||
raw_spin_unlock(&base->lock);
|
||||
|
||||
return cmp_next_hrtimer_event(basem, expires);
|
||||
}
|
||||
@@ -1590,7 +1590,7 @@ static inline void __run_timers(struct timer_base *base)
|
||||
if (!time_after_eq(jiffies, base->clk))
|
||||
return;
|
||||
|
||||
spin_lock_irq(&base->lock);
|
||||
raw_spin_lock_irq(&base->lock);
|
||||
|
||||
while (time_after_eq(jiffies, base->clk)) {
|
||||
|
||||
@@ -1601,7 +1601,7 @@ static inline void __run_timers(struct timer_base *base)
|
||||
expire_timers(base, heads + levels);
|
||||
}
|
||||
base->running_timer = NULL;
|
||||
spin_unlock_irq(&base->lock);
|
||||
raw_spin_unlock_irq(&base->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1786,16 +1786,16 @@ int timers_dead_cpu(unsigned int cpu)
|
||||
* The caller is globally serialized and nobody else
|
||||
* takes two locks at once, deadlock is not possible.
|
||||
*/
|
||||
spin_lock_irq(&new_base->lock);
|
||||
spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
|
||||
raw_spin_lock_irq(&new_base->lock);
|
||||
raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
BUG_ON(old_base->running_timer);
|
||||
|
||||
for (i = 0; i < WHEEL_SIZE; i++)
|
||||
migrate_timer_list(new_base, old_base->vectors + i);
|
||||
|
||||
spin_unlock(&old_base->lock);
|
||||
spin_unlock_irq(&new_base->lock);
|
||||
raw_spin_unlock(&old_base->lock);
|
||||
raw_spin_unlock_irq(&new_base->lock);
|
||||
put_cpu_ptr(&timer_bases);
|
||||
}
|
||||
return 0;
|
||||
@@ -1811,7 +1811,7 @@ static void __init init_timer_cpu(int cpu)
|
||||
for (i = 0; i < NR_BASES; i++) {
|
||||
base = per_cpu_ptr(&timer_bases[i], cpu);
|
||||
base->cpu = cpu;
|
||||
spin_lock_init(&base->lock);
|
||||
raw_spin_lock_init(&base->lock);
|
||||
base->clk = jiffies;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user