aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 16:33:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 16:33:57 -0400
commit59b60185b4a1adc46b115291dc34af2186cc9678 (patch)
tree681a5294b7c3f9013b6a5644cbbc74db4ec8d459
parent9bd42183b951051f73de121f7ee17091e7d26fbb (diff)
parentd4af6d933ccffd24286528f04d5c39e702c8580f (diff)
Merge branch 'timers-nohz-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull nohz updates from Ingo Molnar: "The main changes in this cycle relate to fixing another bad (but sporadic and hard to detect) interaction between the dynticks scheduler tick and hrtimers, plus related improvements to better detection and handling of similar problems - by Frédéric Weisbecker" * 'timers-nohz-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: nohz: Fix spurious warning when hrtimer and clockevent get out of sync nohz: Fix buggy tick delay on IRQ storms nohz: Reset next_tick cache even when the timer has no regs nohz: Fix collision between tick and other hrtimers, again nohz: Add hrtimer sanity check
-rw-r--r--kernel/time/tick-sched.c63
-rw-r--r--kernel/time/tick-sched.h2
2 files changed, 42 insertions, 23 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index db023e9cbb25..c7a899c5ce64 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -150,6 +150,12 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
150 touch_softlockup_watchdog_sched(); 150 touch_softlockup_watchdog_sched();
151 if (is_idle_task(current)) 151 if (is_idle_task(current))
152 ts->idle_jiffies++; 152 ts->idle_jiffies++;
153 /*
154 * In case the current tick fired too early past its expected
155 * expiration, make sure we don't bypass the next clock reprogramming
156 * to the same deadline.
157 */
158 ts->next_tick = 0;
153 } 159 }
154#endif 160#endif
155 update_process_times(user_mode(regs)); 161 update_process_times(user_mode(regs));
@@ -660,6 +666,12 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
660 hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); 666 hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED);
661 else 667 else
662 tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); 668 tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
669
670 /*
671 * Reset to make sure next tick stop doesn't get fooled by past
672 * cached clock deadline.
673 */
674 ts->next_tick = 0;
663} 675}
664 676
665static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, 677static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
@@ -701,8 +713,6 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
701 */ 713 */
702 delta = next_tick - basemono; 714 delta = next_tick - basemono;
703 if (delta <= (u64)TICK_NSEC) { 715 if (delta <= (u64)TICK_NSEC) {
704 tick = 0;
705
706 /* 716 /*
707 * Tell the timer code that the base is not idle, i.e. undo 717 * Tell the timer code that the base is not idle, i.e. undo
708 * the effect of get_next_timer_interrupt(): 718 * the effect of get_next_timer_interrupt():
@@ -712,23 +722,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
712 * We've not stopped the tick yet, and there's a timer in the 722 * We've not stopped the tick yet, and there's a timer in the
713 * next period, so no point in stopping it either, bail. 723 * next period, so no point in stopping it either, bail.
714 */ 724 */
715 if (!ts->tick_stopped) 725 if (!ts->tick_stopped) {
716 goto out; 726 tick = 0;
717
718 /*
719 * If, OTOH, we did stop it, but there's a pending (expired)
720 * timer reprogram the timer hardware to fire now.
721 *
722 * We will not restart the tick proper, just prod the timer
723 * hardware into firing an interrupt to process the pending
724 * timers. Just like tick_irq_exit() will not restart the tick
725 * for 'normal' interrupts.
726 *
727 * Only once we exit the idle loop will we re-enable the tick,
728 * see tick_nohz_idle_exit().
729 */
730 if (delta == 0) {
731 tick_nohz_restart(ts, now);
732 goto out; 727 goto out;
733 } 728 }
734 } 729 }
@@ -771,8 +766,16 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
771 tick = expires; 766 tick = expires;
772 767
773 /* Skip reprogram of event if its not changed */ 768 /* Skip reprogram of event if its not changed */
774 if (ts->tick_stopped && (expires == dev->next_event)) 769 if (ts->tick_stopped && (expires == ts->next_tick)) {
775 goto out; 770 /* Sanity check: make sure clockevent is actually programmed */
771 if (tick == KTIME_MAX || ts->next_tick == hrtimer_get_expires(&ts->sched_timer))
772 goto out;
773
774 WARN_ON_ONCE(1);
775 printk_once("basemono: %llu ts->next_tick: %llu dev->next_event: %llu timer->active: %d timer->expires: %llu\n",
776 basemono, ts->next_tick, dev->next_event,
777 hrtimer_active(&ts->sched_timer), hrtimer_get_expires(&ts->sched_timer));
778 }
776 779
777 /* 780 /*
778 * nohz_stop_sched_tick can be called several times before 781 * nohz_stop_sched_tick can be called several times before
@@ -790,6 +793,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
790 trace_tick_stop(1, TICK_DEP_MASK_NONE); 793 trace_tick_stop(1, TICK_DEP_MASK_NONE);
791 } 794 }
792 795
796 ts->next_tick = tick;
797
793 /* 798 /*
794 * If the expiration time == KTIME_MAX, then we simply stop 799 * If the expiration time == KTIME_MAX, then we simply stop
795 * the tick timer. 800 * the tick timer.
@@ -800,12 +805,17 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
800 goto out; 805 goto out;
801 } 806 }
802 807
808 hrtimer_set_expires(&ts->sched_timer, tick);
809
803 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) 810 if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
804 hrtimer_start(&ts->sched_timer, tick, HRTIMER_MODE_ABS_PINNED); 811 hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED);
805 else 812 else
806 tick_program_event(tick, 1); 813 tick_program_event(tick, 1);
807out: 814out:
808 /* Update the estimated sleep length */ 815 /*
816 * Update the estimated sleep length until the next timer
817 * (not only the tick).
818 */
809 ts->sleep_length = ktime_sub(dev->next_event, now); 819 ts->sleep_length = ktime_sub(dev->next_event, now);
810 return tick; 820 return tick;
811} 821}
@@ -863,6 +873,11 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
863 if (unlikely(!cpu_online(cpu))) { 873 if (unlikely(!cpu_online(cpu))) {
864 if (cpu == tick_do_timer_cpu) 874 if (cpu == tick_do_timer_cpu)
865 tick_do_timer_cpu = TICK_DO_TIMER_NONE; 875 tick_do_timer_cpu = TICK_DO_TIMER_NONE;
876 /*
877 * Make sure the CPU doesn't get fooled by obsolete tick
878 * deadline if it comes back online later.
879 */
880 ts->next_tick = 0;
866 return false; 881 return false;
867 } 882 }
868 883
@@ -1173,6 +1188,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
1173 */ 1188 */
1174 if (regs) 1189 if (regs)
1175 tick_sched_handle(ts, regs); 1190 tick_sched_handle(ts, regs);
1191 else
1192 ts->next_tick = 0;
1176 1193
1177 /* No need to reprogram if we are in idle or full dynticks mode */ 1194 /* No need to reprogram if we are in idle or full dynticks mode */
1178 if (unlikely(ts->tick_stopped)) 1195 if (unlikely(ts->tick_stopped))
diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h
index bf38226e5c17..075444e3d48e 100644
--- a/kernel/time/tick-sched.h
+++ b/kernel/time/tick-sched.h
@@ -27,6 +27,7 @@ enum tick_nohz_mode {
27 * timer is modified for nohz sleeps. This is necessary 27 * timer is modified for nohz sleeps. This is necessary
28 * to resume the tick timer operation in the timeline 28 * to resume the tick timer operation in the timeline
29 * when the CPU returns from nohz sleep. 29 * when the CPU returns from nohz sleep.
30 * @next_tick: Next tick to be fired when in dynticks mode.
30 * @tick_stopped: Indicator that the idle tick has been stopped 31 * @tick_stopped: Indicator that the idle tick has been stopped
31 * @idle_jiffies: jiffies at the entry to idle for idle time accounting 32 * @idle_jiffies: jiffies at the entry to idle for idle time accounting
32 * @idle_calls: Total number of idle calls 33 * @idle_calls: Total number of idle calls
@@ -44,6 +45,7 @@ struct tick_sched {
44 unsigned long check_clocks; 45 unsigned long check_clocks;
45 enum tick_nohz_mode nohz_mode; 46 enum tick_nohz_mode nohz_mode;
46 ktime_t last_tick; 47 ktime_t last_tick;
48 ktime_t next_tick;
47 int inidle; 49 int inidle;
48 int tick_stopped; 50 int tick_stopped;
49 unsigned long idle_jiffies; 51 unsigned long idle_jiffies;