futex: Fix uninterruptible loop due to gate_area
[linux-2.6.git] / kernel / posix-timers.c
index 4f71382..4556182 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
@@ -167,28 +157,6 @@ 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))
-
-/*
- * 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;
-       return 1;
-}
-
 /* Get clock_realtime */
 static int posix_clock_realtime_get(clockid_t which_clock, struct timespec *tp)
 {
@@ -203,6 +171,12 @@ static int posix_clock_realtime_set(const clockid_t which_clock,
        return do_sys_settimeofday(tp, NULL);
 }
 
+static int posix_clock_realtime_adj(const clockid_t which_clock,
+                                   struct timex *t)
+{
+       return do_adjtimex(t);
+}
+
 /*
  * Get monotonic time for posix timers
  */
@@ -213,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)
 {
@@ -240,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 ;)
  */
@@ -249,9 +231,13 @@ static __init int init_posix_timers(void)
                .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,
@@ -259,6 +245,9 @@ static __init int init_posix_timers(void)
                .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,
@@ -272,12 +261,23 @@ static __init int init_posix_timers(void)
                .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,
@@ -313,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)
@@ -453,7 +453,8 @@ 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(KERN_WARNING "POSIX clock register failed for clock_id %d\n",
@@ -474,7 +475,7 @@ void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock)
 
        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)
 {
@@ -490,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)
@@ -502,13 +510,14 @@ 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;
@@ -629,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;
 }
@@ -710,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;
 }
 
 /*
@@ -814,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;
@@ -829,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) {
@@ -845,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;
 
@@ -856,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. */
@@ -961,6 +980,29 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
        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)
 {
@@ -1017,7 +1059,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
  */
 long clock_nanosleep_restart(struct restart_block *restart_block)
 {
-       clockid_t which_clock = restart_block->nanosleep.index;
+       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))