]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/posix-timers.c
sched: Reorder root_domain to remove 64 bit alignment padding
[linux-2.6.git] / kernel / posix-timers.c
index ee69b216d5c3b9e179628ea7eb1126334f021df1..4556182527f38fe88dba74dd753cec5ed0112785 100644 (file)
@@ -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>
@@ -102,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
@@ -116,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
@@ -146,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 *);
@@ -166,70 +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,
-                                  const 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)
+static int posix_clock_realtime_adj(const clockid_t which_clock,
+                                   struct timex *t)
 {
-       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;
-}
-
-/*
- * Return nonzero if we know a priori this clockid_t value is bogus.
- */
-static inline int invalid_clockid(const clockid_t which_clock)
-{
-       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);
 }
 
 /*
@@ -242,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)
 {
@@ -269,6 +214,14 @@ 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 ;)
  */
@@ -276,38 +229,55 @@ static __init int init_posix_timers(void)
 {
        struct k_clock clock_realtime = {
                .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,
                .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,
        };
        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,
        };
        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,
+       };
+       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,
@@ -343,7 +313,7 @@ static void schedule_next_timer(struct k_itimer *timr)
  * restarted (i.e. we have flagged this in the sys_private entry of the
  * info block).
  *
- * To protect aginst the timer going away while the interrupt is queued,
+ * To protect against the timer going away while the interrupt is queued,
  * we require that the it_requeue_pending flag be set.
  */
 void do_schedule_next_timer(struct siginfo *info)
@@ -483,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)
 {
@@ -509,6 +491,13 @@ static struct k_itimer * alloc_posix_timer(void)
        return tmr;
 }
 
+static void k_itimer_rcu_free(struct rcu_head *head)
+{
+       struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu);
+
+       kmem_cache_free(posix_timers_cache, tmr);
+}
+
 #define IT_ID_SET      1
 #define IT_ID_NOT_SET  0
 static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
@@ -521,32 +510,42 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
        }
        put_pid(tmr->it_pid);
        sigqueue_free(tmr->sigq);
-       kmem_cache_free(posix_timers_cache, tmr);
+       call_rcu(&tmr->it.rcu, k_itimer_rcu_free);
 }
 
 static struct k_clock *clockid_to_kclock(const clockid_t id)
 {
        if (id < 0)
-               return &clock_posix_cpu;
+               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))
@@ -608,7 +607,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;
 
@@ -618,7 +617,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        spin_unlock_irq(&current->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
@@ -639,22 +638,18 @@ out:
 static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
 {
        struct k_itimer *timr;
-       /*
-        * Watch out here.  We do a irqsave on the idr_lock and pass the
-        * flags part over to the timer lock.  Must not let interrupts in
-        * while we are moving the lock.
-        */
-       spin_lock_irqsave(&idr_lock, *flags);
+
+       rcu_read_lock();
        timr = idr_find(&posix_timers_id, (int)timer_id);
        if (timr) {
-               spin_lock(&timr->it_lock);
+               spin_lock_irqsave(&timr->it_lock, *flags);
                if (timr->it_signal == current->signal) {
-                       spin_unlock(&idr_lock);
+                       rcu_read_unlock();
                        return timr;
                }
-               spin_unlock(&timr->it_lock);
+               spin_unlock_irqrestore(&timr->it_lock, *flags);
        }
-       spin_unlock_irqrestore(&idr_lock, *flags);
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -720,22 +715,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;
 }
 
 /*
@@ -824,6 +825,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;
@@ -839,8 +841,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) {
@@ -855,7 +860,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;
 
@@ -866,7 +871,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. */
@@ -938,58 +947,76 @@ void exit_itimers(struct signal_struct *sig)
        }
 }
 
-/* Not available / possible... functions */
-int do_posix_clock_nosettime(const clockid_t clockid, const struct timespec *tp)
-{
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(do_posix_clock_nosettime);
-
 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;
 }
@@ -1026,23 +1053,17 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
        return kc->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);
-}
-
 /*
  * 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.clockid;
+       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);
 }