aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-01-15 15:00:37 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-01-15 15:00:37 -0500
commita11ce3a4ac0ad78618cddb9ce16def7486f2707d (patch)
tree96f6f9b7f979dcfa94d036d7431fdd799b108638
parent79078c53baabee12dfefb0cfe00ca94cb2c35570 (diff)
parent24b91e360ef521a2808771633d76ebc68bd5604b (diff)
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull NOHZ fix from Ingo Molnar: "This fixes an old NOHZ race where we incorrectly calculate the next timer interrupt in certain circumstances where hrtimers are pending, that can cause hard to reproduce stalled-values artifacts in /proc/stat" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: nohz: Fix collision between tick and other hrtimers
-rw-r--r--kernel/time/tick-sched.c9
-rw-r--r--kernel/time/tick-sched.h2
2 files changed, 9 insertions, 2 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 2c115fdab397..74e0388cc88d 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -767,7 +767,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
767 tick = expires; 767 tick = expires;
768 768
769 /* Skip reprogram of event if its not changed */ 769 /* Skip reprogram of event if its not changed */
770 if (ts->tick_stopped && (expires == dev->next_event)) 770 if (ts->tick_stopped && (expires == ts->next_tick))
771 goto out; 771 goto out;
772 772
773 /* 773 /*
@@ -787,6 +787,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
787 trace_tick_stop(1, TICK_DEP_MASK_NONE); 787 trace_tick_stop(1, TICK_DEP_MASK_NONE);
788 } 788 }
789 789
790 ts->next_tick = tick;
791
790 /* 792 /*
791 * If the expiration time == KTIME_MAX, then we simply stop 793 * If the expiration time == KTIME_MAX, then we simply stop
792 * the tick timer. 794 * the tick timer.
@@ -802,7 +804,10 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
802 else 804 else
803 tick_program_event(tick, 1); 805 tick_program_event(tick, 1);
804out: 806out:
805 /* Update the estimated sleep length */ 807 /*
808 * Update the estimated sleep length until the next timer
809 * (not only the tick).
810 */
806 ts->sleep_length = ktime_sub(dev->next_event, now); 811 ts->sleep_length = ktime_sub(dev->next_event, now);
807 return tick; 812 return tick;
808} 813}
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;