nfsd: track last inode only in use_wgather case
[safe/jmp/linux-2.6] / kernel / hrtimer.c
index 2dc30c5..cb8a15c 100644 (file)
@@ -501,6 +501,13 @@ static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base)
                        continue;
                timer = rb_entry(base->first, struct hrtimer, node);
                expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
+               /*
+                * clock_was_set() has changed base->offset so the
+                * result might be negative. Fix it up to prevent a
+                * false positive in clockevents_program_event()
+                */
+               if (expires.tv64 < 0)
+                       expires.tv64 = 0;
                if (expires.tv64 < cpu_base->expires_next.tv64)
                        cpu_base->expires_next = expires;
        }
@@ -614,7 +621,9 @@ void clock_was_set(void)
  */
 void hres_timers_resume(void)
 {
-       /* Retrigger the CPU local events: */
+       WARN_ONCE(!irqs_disabled(),
+                 KERN_INFO "hres_timers_resume() called with IRQs enabled!");
+
        retrigger_next_event(NULL);
 }
 
@@ -642,14 +651,20 @@ static inline void hrtimer_init_timer_hres(struct hrtimer *timer)
  * and expiry check is done in the hrtimer_interrupt or in the softirq.
  */
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-                                           struct hrtimer_clock_base *base)
+                                           struct hrtimer_clock_base *base,
+                                           int wakeup)
 {
        if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
-               spin_unlock(&base->cpu_base->lock);
-               raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-               spin_lock(&base->cpu_base->lock);
+               if (wakeup) {
+                       spin_unlock(&base->cpu_base->lock);
+                       raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+                       spin_lock(&base->cpu_base->lock);
+               } else
+                       __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+
                return 1;
        }
+
        return 0;
 }
 
@@ -694,7 +709,8 @@ static inline int hrtimer_is_hres_enabled(void) { return 0; }
 static inline int hrtimer_switch_to_hres(void) { return 0; }
 static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-                                           struct hrtimer_clock_base *base)
+                                           struct hrtimer_clock_base *base,
+                                           int wakeup)
 {
        return 0;
 }
@@ -877,20 +893,9 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
        return 0;
 }
 
-/**
- * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
- * @timer:     the timer to be added
- * @tim:       expiry time
- * @delta_ns:  "slack" range for the timer
- * @mode:      expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
- *
- * Returns:
- *  0 on success
- *  1 when the timer was active
- */
-int
-hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_ns,
-                       const enum hrtimer_mode mode)
+int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+               unsigned long delta_ns, const enum hrtimer_mode mode,
+               int wakeup)
 {
        struct hrtimer_clock_base *base, *new_base;
        unsigned long flags;
@@ -931,12 +936,29 @@ hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_n
         * XXX send_remote_softirq() ?
         */
        if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases))
-               hrtimer_enqueue_reprogram(timer, new_base);
+               hrtimer_enqueue_reprogram(timer, new_base, wakeup);
 
        unlock_hrtimer_base(timer, &flags);
 
        return ret;
 }
+
+/**
+ * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
+ * @timer:     the timer to be added
+ * @tim:       expiry time
+ * @delta_ns:  "slack" range for the timer
+ * @mode:      expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ *
+ * Returns:
+ *  0 on success
+ *  1 when the timer was active
+ */
+int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+               unsigned long delta_ns, const enum hrtimer_mode mode)
+{
+       return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1);
+}
 EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
 
 /**
@@ -952,7 +974,7 @@ EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
 int
 hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
 {
-       return hrtimer_start_range_ns(timer, tim, 0, mode);
+       return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
 }
 EXPORT_SYMBOL_GPL(hrtimer_start);
 
@@ -1156,6 +1178,29 @@ static void __run_hrtimer(struct hrtimer *timer)
 
 #ifdef CONFIG_HIGH_RES_TIMERS
 
+static int force_clock_reprogram;
+
+/*
+ * After 5 iteration's attempts, we consider that hrtimer_interrupt()
+ * is hanging, which could happen with something that slows the interrupt
+ * such as the tracing. Then we force the clock reprogramming for each future
+ * hrtimer interrupts to avoid infinite loops and use the min_delta_ns
+ * threshold that we will overwrite.
+ * The next tick event will be scheduled to 3 times we currently spend on
+ * hrtimer_interrupt(). This gives a good compromise, the cpus will spend
+ * 1/4 of their time to process the hrtimer interrupts. This is enough to
+ * let it running without serious starvation.
+ */
+
+static inline void
+hrtimer_interrupt_hanging(struct clock_event_device *dev,
+                       ktime_t try_time)
+{
+       force_clock_reprogram = 1;
+       dev->min_delta_ns = (unsigned long)try_time.tv64 * 3;
+       printk(KERN_WARNING "hrtimer: interrupt too slow, "
+               "forcing clock min delta to %lu ns\n", dev->min_delta_ns);
+}
 /*
  * High resolution timer interrupt
  * Called with interrupts disabled
@@ -1165,6 +1210,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
        struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
        struct hrtimer_clock_base *base;
        ktime_t expires_next, now;
+       int nr_retries = 0;
        int i;
 
        BUG_ON(!cpu_base->hres_active);
@@ -1172,6 +1218,10 @@ void hrtimer_interrupt(struct clock_event_device *dev)
        dev->next_event.tv64 = KTIME_MAX;
 
  retry:
+       /* 5 retries is enough to notice a hang */
+       if (!(++nr_retries % 5))
+               hrtimer_interrupt_hanging(dev, ktime_sub(ktime_get(), now));
+
        now = ktime_get();
 
        expires_next.tv64 = KTIME_MAX;
@@ -1224,7 +1274,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
 
        /* Reprogramming necessary ? */
        if (expires_next.tv64 != KTIME_MAX) {
-               if (tick_program_event(expires_next, 0))
+               if (tick_program_event(expires_next, force_clock_reprogram))
                        goto retry;
        }
 }
@@ -1578,6 +1628,10 @@ static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
+       case CPU_DYING:
+       case CPU_DYING_FROZEN:
+               clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DYING, &scpu);
+               break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
        {