|
@@ -41,6 +41,7 @@
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/compiler.h>
|
|
|
#include <linux/idr.h>
|
|
|
+#include <linux/posix-clock.h>
|
|
|
#include <linux/posix-timers.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/wait.h>
|
|
@@ -81,6 +82,14 @@ static DEFINE_SPINLOCK(idr_lock);
|
|
|
#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"
|
|
|
#endif
|
|
|
|
|
|
+/*
|
|
|
+ * parisc wants ENOTSUP instead of EOPNOTSUPP
|
|
|
+ */
|
|
|
+#ifndef ENOTSUP
|
|
|
+# define ENANOSLEEP_NOTSUP EOPNOTSUPP
|
|
|
+#else
|
|
|
+# define ENANOSLEEP_NOTSUP ENOTSUP
|
|
|
+#endif
|
|
|
|
|
|
/*
|
|
|
* The timer ID is turned into a timer address by idr_find().
|
|
@@ -94,11 +103,7 @@ static DEFINE_SPINLOCK(idr_lock);
|
|
|
/*
|
|
|
* CLOCKs: The POSIX standard calls for a couple of clocks and allows us
|
|
|
* to implement others. This structure defines the various
|
|
|
- * clocks and allows the possibility of adding others. We
|
|
|
- * provide an interface to add clocks to the table and expect
|
|
|
- * the "arch" code to add at least one clock that is high
|
|
|
- * resolution. Here we define the standard CLOCK_REALTIME as a
|
|
|
- * 1/HZ resolution clock.
|
|
|
+ * clocks.
|
|
|
*
|
|
|
* RESOLUTION: Clock resolution is used to round up timer and interval
|
|
|
* times, NOT to report clock times, which are reported with as
|
|
@@ -108,20 +113,13 @@ static DEFINE_SPINLOCK(idr_lock);
|
|
|
* necessary code is written. The standard says we should say
|
|
|
* something about this issue in the documentation...
|
|
|
*
|
|
|
- * FUNCTIONS: The CLOCKs structure defines possible functions to handle
|
|
|
- * various clock functions. For clocks that use the standard
|
|
|
- * system timer code these entries should be NULL. This will
|
|
|
- * allow dispatch without the overhead of indirect function
|
|
|
- * calls. CLOCKS that depend on other sources (e.g. WWV or GPS)
|
|
|
- * must supply functions here, even if the function just returns
|
|
|
- * ENOSYS. The standard POSIX timer management code assumes the
|
|
|
- * following: 1.) The k_itimer struct (sched.h) is used for the
|
|
|
- * timer. 2.) The list, it_lock, it_clock, it_id and it_pid
|
|
|
- * fields are not modified by timer code.
|
|
|
+ * FUNCTIONS: The CLOCKs structure defines possible functions to
|
|
|
+ * handle various clock functions.
|
|
|
*
|
|
|
- * At this time all functions EXCEPT clock_nanosleep can be
|
|
|
- * redirected by the CLOCKS structure. Clock_nanosleep is in
|
|
|
- * there, but the code ignores it.
|
|
|
+ * The standard POSIX timer management code assumes the
|
|
|
+ * following: 1.) The k_itimer struct (sched.h) is used for
|
|
|
+ * the timer. 2.) The list, it_lock, it_clock, it_id and
|
|
|
+ * it_pid fields are not modified by timer code.
|
|
|
*
|
|
|
* Permissions: It is assumed that the clock_settime() function defined
|
|
|
* for each clock will take care of permission checks. Some
|
|
@@ -138,6 +136,7 @@ static struct k_clock posix_clocks[MAX_CLOCKS];
|
|
|
*/
|
|
|
static int common_nsleep(const clockid_t, int flags, struct timespec *t,
|
|
|
struct timespec __user *rmtp);
|
|
|
+static int common_timer_create(struct k_itimer *new_timer);
|
|
|
static void common_timer_get(struct k_itimer *, struct itimerspec *);
|
|
|
static int common_timer_set(struct k_itimer *, int,
|
|
|
struct itimerspec *, struct itimerspec *);
|
|
@@ -158,76 +157,24 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
|
|
|
spin_unlock_irqrestore(&timr->it_lock, flags);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Call the k_clock hook function if non-null, or the default function.
|
|
|
- */
|
|
|
-#define CLOCK_DISPATCH(clock, call, arglist) \
|
|
|
- ((clock) < 0 ? posix_cpu_##call arglist : \
|
|
|
- (posix_clocks[clock].call != NULL \
|
|
|
- ? (*posix_clocks[clock].call) arglist : common_##call arglist))
|
|
|
-
|
|
|
-/*
|
|
|
- * Default clock hook functions when the struct k_clock passed
|
|
|
- * to register_posix_clock leaves a function pointer null.
|
|
|
- *
|
|
|
- * The function common_CALL is the default implementation for
|
|
|
- * the function pointer CALL in struct k_clock.
|
|
|
- */
|
|
|
-
|
|
|
-static inline int common_clock_getres(const clockid_t which_clock,
|
|
|
- struct timespec *tp)
|
|
|
-{
|
|
|
- tp->tv_sec = 0;
|
|
|
- tp->tv_nsec = posix_clocks[which_clock].res;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Get real time for posix timers
|
|
|
- */
|
|
|
-static int common_clock_get(clockid_t which_clock, struct timespec *tp)
|
|
|
+/* Get clock_realtime */
|
|
|
+static int posix_clock_realtime_get(clockid_t which_clock, struct timespec *tp)
|
|
|
{
|
|
|
ktime_get_real_ts(tp);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static inline int common_clock_set(const clockid_t which_clock,
|
|
|
- struct timespec *tp)
|
|
|
+/* Set clock_realtime */
|
|
|
+static int posix_clock_realtime_set(const clockid_t which_clock,
|
|
|
+ const struct timespec *tp)
|
|
|
{
|
|
|
return do_sys_settimeofday(tp, NULL);
|
|
|
}
|
|
|
|
|
|
-static int common_timer_create(struct k_itimer *new_timer)
|
|
|
-{
|
|
|
- hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int no_timer_create(struct k_itimer *new_timer)
|
|
|
-{
|
|
|
- return -EOPNOTSUPP;
|
|
|
-}
|
|
|
-
|
|
|
-static int no_nsleep(const clockid_t which_clock, int flags,
|
|
|
- struct timespec *tsave, struct timespec __user *rmtp)
|
|
|
-{
|
|
|
- return -EOPNOTSUPP;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Return nonzero if we know a priori this clockid_t value is bogus.
|
|
|
- */
|
|
|
-static inline int invalid_clockid(const clockid_t which_clock)
|
|
|
+static int posix_clock_realtime_adj(const clockid_t which_clock,
|
|
|
+ struct timex *t)
|
|
|
{
|
|
|
- if (which_clock < 0) /* CPU clock, posix_cpu_* will check it */
|
|
|
- return 0;
|
|
|
- if ((unsigned) which_clock >= MAX_CLOCKS)
|
|
|
- return 1;
|
|
|
- if (posix_clocks[which_clock].clock_getres != NULL)
|
|
|
- return 0;
|
|
|
- if (posix_clocks[which_clock].res != 0)
|
|
|
- return 0;
|
|
|
- return 1;
|
|
|
+ return do_adjtimex(t);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -240,7 +187,7 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Get monotonic time for posix timers
|
|
|
+ * Get monotonic-raw time for posix timers
|
|
|
*/
|
|
|
static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
|
|
|
{
|
|
@@ -267,46 +214,70 @@ static int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp
|
|
|
*tp = ktime_to_timespec(KTIME_LOW_RES);
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+static int posix_get_boottime(const clockid_t which_clock, struct timespec *tp)
|
|
|
+{
|
|
|
+ get_monotonic_boottime(tp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Initialize everything, well, just everything in Posix clocks/timers ;)
|
|
|
*/
|
|
|
static __init int init_posix_timers(void)
|
|
|
{
|
|
|
struct k_clock clock_realtime = {
|
|
|
- .clock_getres = hrtimer_get_res,
|
|
|
+ .clock_getres = hrtimer_get_res,
|
|
|
+ .clock_get = posix_clock_realtime_get,
|
|
|
+ .clock_set = posix_clock_realtime_set,
|
|
|
+ .clock_adj = posix_clock_realtime_adj,
|
|
|
+ .nsleep = common_nsleep,
|
|
|
+ .nsleep_restart = hrtimer_nanosleep_restart,
|
|
|
+ .timer_create = common_timer_create,
|
|
|
+ .timer_set = common_timer_set,
|
|
|
+ .timer_get = common_timer_get,
|
|
|
+ .timer_del = common_timer_del,
|
|
|
};
|
|
|
struct k_clock clock_monotonic = {
|
|
|
- .clock_getres = hrtimer_get_res,
|
|
|
- .clock_get = posix_ktime_get_ts,
|
|
|
- .clock_set = do_posix_clock_nosettime,
|
|
|
+ .clock_getres = hrtimer_get_res,
|
|
|
+ .clock_get = posix_ktime_get_ts,
|
|
|
+ .nsleep = common_nsleep,
|
|
|
+ .nsleep_restart = hrtimer_nanosleep_restart,
|
|
|
+ .timer_create = common_timer_create,
|
|
|
+ .timer_set = common_timer_set,
|
|
|
+ .timer_get = common_timer_get,
|
|
|
+ .timer_del = common_timer_del,
|
|
|
};
|
|
|
struct k_clock clock_monotonic_raw = {
|
|
|
- .clock_getres = hrtimer_get_res,
|
|
|
- .clock_get = posix_get_monotonic_raw,
|
|
|
- .clock_set = do_posix_clock_nosettime,
|
|
|
- .timer_create = no_timer_create,
|
|
|
- .nsleep = no_nsleep,
|
|
|
+ .clock_getres = hrtimer_get_res,
|
|
|
+ .clock_get = posix_get_monotonic_raw,
|
|
|
};
|
|
|
struct k_clock clock_realtime_coarse = {
|
|
|
- .clock_getres = posix_get_coarse_res,
|
|
|
- .clock_get = posix_get_realtime_coarse,
|
|
|
- .clock_set = do_posix_clock_nosettime,
|
|
|
- .timer_create = no_timer_create,
|
|
|
- .nsleep = no_nsleep,
|
|
|
+ .clock_getres = posix_get_coarse_res,
|
|
|
+ .clock_get = posix_get_realtime_coarse,
|
|
|
};
|
|
|
struct k_clock clock_monotonic_coarse = {
|
|
|
- .clock_getres = posix_get_coarse_res,
|
|
|
- .clock_get = posix_get_monotonic_coarse,
|
|
|
- .clock_set = do_posix_clock_nosettime,
|
|
|
- .timer_create = no_timer_create,
|
|
|
- .nsleep = no_nsleep,
|
|
|
+ .clock_getres = posix_get_coarse_res,
|
|
|
+ .clock_get = posix_get_monotonic_coarse,
|
|
|
+ };
|
|
|
+ struct k_clock clock_boottime = {
|
|
|
+ .clock_getres = hrtimer_get_res,
|
|
|
+ .clock_get = posix_get_boottime,
|
|
|
+ .nsleep = common_nsleep,
|
|
|
+ .nsleep_restart = hrtimer_nanosleep_restart,
|
|
|
+ .timer_create = common_timer_create,
|
|
|
+ .timer_set = common_timer_set,
|
|
|
+ .timer_get = common_timer_get,
|
|
|
+ .timer_del = common_timer_del,
|
|
|
};
|
|
|
|
|
|
- register_posix_clock(CLOCK_REALTIME, &clock_realtime);
|
|
|
- register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
|
|
|
- register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
|
|
|
- register_posix_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse);
|
|
|
- register_posix_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse);
|
|
|
+ posix_timers_register_clock(CLOCK_REALTIME, &clock_realtime);
|
|
|
+ posix_timers_register_clock(CLOCK_MONOTONIC, &clock_monotonic);
|
|
|
+ posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
|
|
|
+ posix_timers_register_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse);
|
|
|
+ posix_timers_register_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse);
|
|
|
+ posix_timers_register_clock(CLOCK_BOOTTIME, &clock_boottime);
|
|
|
|
|
|
posix_timers_cache = kmem_cache_create("posix_timers_cache",
|
|
|
sizeof (struct k_itimer), 0, SLAB_PANIC,
|
|
@@ -482,17 +453,29 @@ static struct pid *good_sigevent(sigevent_t * event)
|
|
|
return task_pid(rtn);
|
|
|
}
|
|
|
|
|
|
-void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock)
|
|
|
+void posix_timers_register_clock(const clockid_t clock_id,
|
|
|
+ struct k_clock *new_clock)
|
|
|
{
|
|
|
if ((unsigned) clock_id >= MAX_CLOCKS) {
|
|
|
- printk("POSIX clock register failed for clock_id %d\n",
|
|
|
+ printk(KERN_WARNING "POSIX clock register failed for clock_id %d\n",
|
|
|
+ clock_id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!new_clock->clock_get) {
|
|
|
+ printk(KERN_WARNING "POSIX clock id %d lacks clock_get()\n",
|
|
|
+ clock_id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!new_clock->clock_getres) {
|
|
|
+ printk(KERN_WARNING "POSIX clock id %d lacks clock_getres()\n",
|
|
|
clock_id);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
posix_clocks[clock_id] = *new_clock;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(register_posix_clock);
|
|
|
+EXPORT_SYMBOL_GPL(posix_timers_register_clock);
|
|
|
|
|
|
static struct k_itimer * alloc_posix_timer(void)
|
|
|
{
|
|
@@ -523,19 +506,39 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
|
|
|
kmem_cache_free(posix_timers_cache, tmr);
|
|
|
}
|
|
|
|
|
|
+static struct k_clock *clockid_to_kclock(const clockid_t id)
|
|
|
+{
|
|
|
+ if (id < 0)
|
|
|
+ return (id & CLOCKFD_MASK) == CLOCKFD ?
|
|
|
+ &clock_posix_dynamic : &clock_posix_cpu;
|
|
|
+
|
|
|
+ if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
|
|
|
+ return NULL;
|
|
|
+ return &posix_clocks[id];
|
|
|
+}
|
|
|
+
|
|
|
+static int common_timer_create(struct k_itimer *new_timer)
|
|
|
+{
|
|
|
+ hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Create a POSIX.1b interval timer. */
|
|
|
|
|
|
SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
|
|
|
struct sigevent __user *, timer_event_spec,
|
|
|
timer_t __user *, created_timer_id)
|
|
|
{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
struct k_itimer *new_timer;
|
|
|
int error, new_timer_id;
|
|
|
sigevent_t event;
|
|
|
int it_id_set = IT_ID_NOT_SET;
|
|
|
|
|
|
- if (invalid_clockid(which_clock))
|
|
|
+ if (!kc)
|
|
|
return -EINVAL;
|
|
|
+ if (!kc->timer_create)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
|
|
new_timer = alloc_posix_timer();
|
|
|
if (unlikely(!new_timer))
|
|
@@ -597,7 +600,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
|
|
|
+ error = kc->timer_create(new_timer);
|
|
|
if (error)
|
|
|
goto out;
|
|
|
|
|
@@ -607,7 +610,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
|
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
|
|
return 0;
|
|
|
- /*
|
|
|
+ /*
|
|
|
* In the case of the timer belonging to another task, after
|
|
|
* the task is unlocked, the timer is owned by the other task
|
|
|
* and may cease to exist at any time. Don't use or modify
|
|
@@ -709,22 +712,28 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
|
|
|
SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
|
|
|
struct itimerspec __user *, setting)
|
|
|
{
|
|
|
- struct k_itimer *timr;
|
|
|
struct itimerspec cur_setting;
|
|
|
+ struct k_itimer *timr;
|
|
|
+ struct k_clock *kc;
|
|
|
unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
timr = lock_timer(timer_id, &flags);
|
|
|
if (!timr)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- CLOCK_DISPATCH(timr->it_clock, timer_get, (timr, &cur_setting));
|
|
|
+ kc = clockid_to_kclock(timr->it_clock);
|
|
|
+ if (WARN_ON_ONCE(!kc || !kc->timer_get))
|
|
|
+ ret = -EINVAL;
|
|
|
+ else
|
|
|
+ kc->timer_get(timr, &cur_setting);
|
|
|
|
|
|
unlock_timer(timr, flags);
|
|
|
|
|
|
- if (copy_to_user(setting, &cur_setting, sizeof (cur_setting)))
|
|
|
+ if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -813,6 +822,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
|
|
|
int error = 0;
|
|
|
unsigned long flag;
|
|
|
struct itimerspec *rtn = old_setting ? &old_spec : NULL;
|
|
|
+ struct k_clock *kc;
|
|
|
|
|
|
if (!new_setting)
|
|
|
return -EINVAL;
|
|
@@ -828,8 +838,11 @@ retry:
|
|
|
if (!timr)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- error = CLOCK_DISPATCH(timr->it_clock, timer_set,
|
|
|
- (timr, flags, &new_spec, rtn));
|
|
|
+ kc = clockid_to_kclock(timr->it_clock);
|
|
|
+ if (WARN_ON_ONCE(!kc || !kc->timer_set))
|
|
|
+ error = -EINVAL;
|
|
|
+ else
|
|
|
+ error = kc->timer_set(timr, flags, &new_spec, rtn);
|
|
|
|
|
|
unlock_timer(timr, flag);
|
|
|
if (error == TIMER_RETRY) {
|
|
@@ -844,7 +857,7 @@ retry:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-static inline int common_timer_del(struct k_itimer *timer)
|
|
|
+static int common_timer_del(struct k_itimer *timer)
|
|
|
{
|
|
|
timer->it.real.interval.tv64 = 0;
|
|
|
|
|
@@ -855,7 +868,11 @@ static inline int common_timer_del(struct k_itimer *timer)
|
|
|
|
|
|
static inline int timer_delete_hook(struct k_itimer *timer)
|
|
|
{
|
|
|
- return CLOCK_DISPATCH(timer->it_clock, timer_del, (timer));
|
|
|
+ struct k_clock *kc = clockid_to_kclock(timer->it_clock);
|
|
|
+
|
|
|
+ if (WARN_ON_ONCE(!kc || !kc->timer_del))
|
|
|
+ return -EINVAL;
|
|
|
+ return kc->timer_del(timer);
|
|
|
}
|
|
|
|
|
|
/* Delete a POSIX.1b interval timer. */
|
|
@@ -927,69 +944,76 @@ void exit_itimers(struct signal_struct *sig)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Not available / possible... functions */
|
|
|
-int do_posix_clock_nosettime(const clockid_t clockid, struct timespec *tp)
|
|
|
-{
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(do_posix_clock_nosettime);
|
|
|
-
|
|
|
-int do_posix_clock_nonanosleep(const clockid_t clock, int flags,
|
|
|
- struct timespec *t, struct timespec __user *r)
|
|
|
-{
|
|
|
-#ifndef ENOTSUP
|
|
|
- return -EOPNOTSUPP; /* aka ENOTSUP in userland for POSIX */
|
|
|
-#else /* parisc does define it separately. */
|
|
|
- return -ENOTSUP;
|
|
|
-#endif
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep);
|
|
|
-
|
|
|
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
|
|
|
const struct timespec __user *, tp)
|
|
|
{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
struct timespec new_tp;
|
|
|
|
|
|
- if (invalid_clockid(which_clock))
|
|
|
+ if (!kc || !kc->clock_set)
|
|
|
return -EINVAL;
|
|
|
+
|
|
|
if (copy_from_user(&new_tp, tp, sizeof (*tp)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp));
|
|
|
+ return kc->clock_set(which_clock, &new_tp);
|
|
|
}
|
|
|
|
|
|
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
|
|
|
struct timespec __user *,tp)
|
|
|
{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
struct timespec kernel_tp;
|
|
|
int error;
|
|
|
|
|
|
- if (invalid_clockid(which_clock))
|
|
|
+ if (!kc)
|
|
|
return -EINVAL;
|
|
|
- error = CLOCK_DISPATCH(which_clock, clock_get,
|
|
|
- (which_clock, &kernel_tp));
|
|
|
+
|
|
|
+ error = kc->clock_get(which_clock, &kernel_tp);
|
|
|
+
|
|
|
if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
|
|
|
error = -EFAULT;
|
|
|
|
|
|
return error;
|
|
|
+}
|
|
|
+
|
|
|
+SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
|
|
|
+ struct timex __user *, utx)
|
|
|
+{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
+ struct timex ktx;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (!kc)
|
|
|
+ return -EINVAL;
|
|
|
+ if (!kc->clock_adj)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (copy_from_user(&ktx, utx, sizeof(ktx)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ err = kc->clock_adj(which_clock, &ktx);
|
|
|
+
|
|
|
+ if (!err && copy_to_user(utx, &ktx, sizeof(ktx)))
|
|
|
+ return -EFAULT;
|
|
|
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
|
|
|
struct timespec __user *, tp)
|
|
|
{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
struct timespec rtn_tp;
|
|
|
int error;
|
|
|
|
|
|
- if (invalid_clockid(which_clock))
|
|
|
+ if (!kc)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- error = CLOCK_DISPATCH(which_clock, clock_getres,
|
|
|
- (which_clock, &rtn_tp));
|
|
|
+ error = kc->clock_getres(which_clock, &rtn_tp);
|
|
|
|
|
|
- if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) {
|
|
|
+ if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp)))
|
|
|
error = -EFAULT;
|
|
|
- }
|
|
|
|
|
|
return error;
|
|
|
}
|
|
@@ -1009,10 +1033,13 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
|
|
|
const struct timespec __user *, rqtp,
|
|
|
struct timespec __user *, rmtp)
|
|
|
{
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
struct timespec t;
|
|
|
|
|
|
- if (invalid_clockid(which_clock))
|
|
|
+ if (!kc)
|
|
|
return -EINVAL;
|
|
|
+ if (!kc->nsleep)
|
|
|
+ return -ENANOSLEEP_NOTSUP;
|
|
|
|
|
|
if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
|
|
|
return -EFAULT;
|
|
@@ -1020,27 +1047,20 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
|
|
|
if (!timespec_valid(&t))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return CLOCK_DISPATCH(which_clock, nsleep,
|
|
|
- (which_clock, flags, &t, rmtp));
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * nanosleep_restart for monotonic and realtime clocks
|
|
|
- */
|
|
|
-static int common_nsleep_restart(struct restart_block *restart_block)
|
|
|
-{
|
|
|
- return hrtimer_nanosleep_restart(restart_block);
|
|
|
+ return kc->nsleep(which_clock, flags, &t, rmtp);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* This will restart clock_nanosleep. This is required only by
|
|
|
* compat_clock_nanosleep_restart for now.
|
|
|
*/
|
|
|
-long
|
|
|
-clock_nanosleep_restart(struct restart_block *restart_block)
|
|
|
+long clock_nanosleep_restart(struct restart_block *restart_block)
|
|
|
{
|
|
|
- clockid_t which_clock = restart_block->arg0;
|
|
|
+ clockid_t which_clock = restart_block->nanosleep.index;
|
|
|
+ struct k_clock *kc = clockid_to_kclock(which_clock);
|
|
|
+
|
|
|
+ if (WARN_ON_ONCE(!kc || !kc->nsleep_restart))
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- return CLOCK_DISPATCH(which_clock, nsleep_restart,
|
|
|
- (restart_block));
|
|
|
+ return kc->nsleep_restart(restart_block);
|
|
|
}
|