Merge tag 'for-linus' of git://github.com/rustyrussell/linux
[linux-flexiantxendom0-3.2.10.git] / kernel / timer.c
index 33a6792..a297ffc 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include <linux/kernel_stat.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/init.h>
@@ -427,6 +427,12 @@ static int timer_fixup_init(void *addr, enum debug_obj_state state)
        }
 }
 
+/* Stub timer callback for improperly used timers. */
+static void stub_timer(unsigned long data)
+{
+       WARN_ON(1);
+}
+
 /*
  * fixup_activate is called when:
  * - an active object is activated
@@ -450,7 +456,8 @@ static int timer_fixup_activate(void *addr, enum debug_obj_state state)
                        debug_object_activate(timer, &timer_debug_descr);
                        return 0;
                } else {
-                       WARN_ON_ONCE(1);
+                       setup_timer(timer, stub_timer, 0);
+                       return 1;
                }
                return 0;
 
@@ -480,12 +487,40 @@ static int timer_fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
+/*
+ * fixup_assert_init is called when:
+ * - an untracked/uninit-ed object is found
+ */
+static int timer_fixup_assert_init(void *addr, enum debug_obj_state state)
+{
+       struct timer_list *timer = addr;
+
+       switch (state) {
+       case ODEBUG_STATE_NOTAVAILABLE:
+               if (timer->entry.prev == TIMER_ENTRY_STATIC) {
+                       /*
+                        * This is not really a fixup. The timer was
+                        * statically initialized. We just make sure that it
+                        * is tracked in the object tracker.
+                        */
+                       debug_object_init(timer, &timer_debug_descr);
+                       return 0;
+               } else {
+                       setup_timer(timer, stub_timer, 0);
+                       return 1;
+               }
+       default:
+               return 0;
+       }
+}
+
 static struct debug_obj_descr timer_debug_descr = {
-       .name           = "timer_list",
-       .debug_hint     = timer_debug_hint,
-       .fixup_init     = timer_fixup_init,
-       .fixup_activate = timer_fixup_activate,
-       .fixup_free     = timer_fixup_free,
+       .name                   = "timer_list",
+       .debug_hint             = timer_debug_hint,
+       .fixup_init             = timer_fixup_init,
+       .fixup_activate         = timer_fixup_activate,
+       .fixup_free             = timer_fixup_free,
+       .fixup_assert_init      = timer_fixup_assert_init,
 };
 
 static inline void debug_timer_init(struct timer_list *timer)
@@ -508,6 +543,11 @@ static inline void debug_timer_free(struct timer_list *timer)
        debug_object_free(timer, &timer_debug_descr);
 }
 
+static inline void debug_timer_assert_init(struct timer_list *timer)
+{
+       debug_object_assert_init(timer, &timer_debug_descr);
+}
+
 static void __init_timer(struct timer_list *timer,
                         const char *name,
                         struct lock_class_key *key);
@@ -531,6 +571,7 @@ EXPORT_SYMBOL_GPL(destroy_timer_on_stack);
 static inline void debug_timer_init(struct timer_list *timer) { }
 static inline void debug_timer_activate(struct timer_list *timer) { }
 static inline void debug_timer_deactivate(struct timer_list *timer) { }
+static inline void debug_timer_assert_init(struct timer_list *timer) { }
 #endif
 
 static inline void debug_init(struct timer_list *timer)
@@ -552,6 +593,11 @@ static inline void debug_deactivate(struct timer_list *timer)
        trace_timer_cancel(timer);
 }
 
+static inline void debug_assert_init(struct timer_list *timer)
+{
+       debug_timer_assert_init(timer);
+}
+
 static void __init_timer(struct timer_list *timer,
                         const char *name,
                         struct lock_class_key *key)
@@ -749,16 +795,15 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
        unsigned long expires_limit, mask;
        int bit;
 
-       expires_limit = expires;
-
        if (timer->slack >= 0) {
                expires_limit = expires + timer->slack;
        } else {
-               unsigned long now = jiffies;
+               long delta = expires - jiffies;
+
+               if (delta < 256)
+                       return expires;
 
-               /* No slack, if already expired else auto slack 0.4% */
-               if (time_after(expires, now))
-                       expires_limit = expires + (expires - now)/256;
+               expires_limit = expires + delta / 256;
        }
        mask = expires ^ expires_limit;
        if (mask == 0)
@@ -795,6 +840,8 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires)
  */
 int mod_timer(struct timer_list *timer, unsigned long expires)
 {
+       expires = apply_slack(timer, expires);
+
        /*
         * This is a common optimization triggered by the
         * networking code - if the timer is re-modified
@@ -803,8 +850,6 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
        if (timer_pending(timer) && timer->expires == expires)
                return 1;
 
-       expires = apply_slack(timer, expires);
-
        return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
 }
 EXPORT_SYMBOL(mod_timer);
@@ -903,6 +948,8 @@ int del_timer(struct timer_list *timer)
        unsigned long flags;
        int ret = 0;
 
+       debug_assert_init(timer);
+
        timer_stats_timer_clear_start_info(timer);
        if (timer_pending(timer)) {
                base = lock_timer_base(timer, &flags);
@@ -933,6 +980,8 @@ int try_to_del_timer_sync(struct timer_list *timer)
        unsigned long flags;
        int ret = -1;
 
+       debug_assert_init(timer);
+
        base = lock_timer_base(timer, &flags);
 
        if (base->running_timer == timer)
@@ -970,6 +1019,25 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
  * add_timer_on(). Upon exit the timer is not queued and the handler is
  * not running on any CPU.
  *
+ * Note: You must not hold locks that are held in interrupt context
+ *   while calling this function. Even if the lock has nothing to do
+ *   with the timer in question.  Here's why:
+ *
+ *    CPU0                             CPU1
+ *    ----                             ----
+ *                                   <SOFTIRQ>
+ *                                   call_timer_fn();
+ *                                     base->running_timer = mytimer;
+ *  spin_lock_irq(somelock);
+ *                                     <IRQ>
+ *                                        spin_lock(somelock);
+ *  del_timer_sync(mytimer);
+ *   while (base->running_timer == mytimer);
+ *
+ * Now del_timer_sync() will never return and never release somelock.
+ * The interrupt on the other CPU is waiting to grab somelock but
+ * it has interrupted the softirq that CPU0 is waiting to finish.
+ *
  * The function returns whether it has deactivated a pending timer or not.
  */
 int del_timer_sync(struct timer_list *timer)
@@ -977,6 +1045,10 @@ int del_timer_sync(struct timer_list *timer)
 #ifdef CONFIG_LOCKDEP
        unsigned long flags;
 
+       /*
+        * If lockdep gives a backtrace here, please reference
+        * the synchronization rules above.
+        */
        local_irq_save(flags);
        lock_map_acquire(&timer->lockdep_map);
        lock_map_release(&timer->lockdep_map);
@@ -1301,19 +1373,6 @@ void run_local_timers(void)
        raise_softirq(TIMER_SOFTIRQ);
 }
 
-/*
- * The 64-bit jiffies value is not atomic - you MUST NOT read it
- * without sampling the sequence number in xtime_lock.
- * jiffies is defined in the linker script...
- */
-
-void do_timer(unsigned long ticks)
-{
-       jiffies_64 += ticks;
-       update_wall_time();
-       calc_global_load(ticks);
-}
-
 #ifdef __ARCH_WANT_SYS_ALARM
 
 /*
@@ -1359,7 +1418,7 @@ SYSCALL_DEFINE0(getppid)
        int pid;
 
        rcu_read_lock();
-       pid = task_tgid_vnr(current->real_parent);
+       pid = task_tgid_vnr(rcu_dereference(current->real_parent));
        rcu_read_unlock();
 
        return pid;