History

Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Thomas Gleixner: "A pile of fixes for long standing issues with the timer wheel and the NOHZ code: - Prevent timer base confusion accross the nohz switch, which can cause unlocked access and data corruption - Reinitialize the stale base clock on cpu hotplug to prevent subtle side effects including rollovers on 32bit - Prevent an interrupt storm when the timer softirq is already pending caused by tick_nohz_stop_sched_tick() - Move the timer start tracepoint to a place where it actually makes sense - Add documentation to timerqueue functions as they caused confusion several times now" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: timerqueue: Document return values of timerqueue_add/del() timers: Invoke timer_start_debug() where it makes sense nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick() timers: Reinitialize per cpu bases on hotplug timers: Use deferrable base independent of base::nohz_active

Linus Torvalds committed 8 years ago

Commit cea92e82 parents 8d517bd 9f4533c6 files · +52 −20Browse files

Unified · Split

6 files
  1. include/linux/cpuhotplug.h +1 −1
  2. include/linux/timer.h +3 −1
  3. kernel/cpu.c +2 −2
  4. kernel/time/tick-sched.c +17 −2
  5. kernel/time/timer.c +24 −11
  6. lib/timerqueue.c +5 −3
include/linux/cpuhotplug.h+1−1
@@ -86,7 +86,7 @@ enum cpuhp_state { · 85 unmodified lines
8686 CPUHP_MM_ZSWP_POOL_PREPARE,
8787 CPUHP_KVM_PPC_BOOK3S_PREPARE,
8888 CPUHP_ZCOMP_PREPARE,
89− CPUHP_TIMERS_DEAD,
89+ CPUHP_TIMERS_PREPARE,
9090 CPUHP_MIPS_SOC_PREPARE,
9191 CPUHP_BP_PREPARE_DYN,
9292 CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20,
include/linux/timer.h+3−1
@@ -207,9 +207,11 @@ unsigned long round_jiffies_up(unsigned long j); · 206 unmodified lines
207207 unsigned long round_jiffies_up_relative(unsigned long j);
208208
209209 #ifdef CONFIG_HOTPLUG_CPU
210+int timers_prepare_cpu(unsigned int cpu);
210211 int timers_dead_cpu(unsigned int cpu);
211212 #else
212−#define timers_dead_cpu NULL
213+#define timers_prepare_cpu NULL
214+#define timers_dead_cpu NULL
213215 #endif
214216
215217 #endif
kernel/cpu.c+2−2
@@ -1277,9 +1277,9 @@ static struct cpuhp_step cpuhp_bp_states[] = { · 1276 unmodified lines
12771277 * before blk_mq_queue_reinit_notify() from notify_dead(),
12781278 * otherwise a RCU stall occurs.
12791279 */
1280− [CPUHP_TIMERS_DEAD] = {
1280+ [CPUHP_TIMERS_PREPARE] = {
12811281 .name = "timers:dead",
1282− .startup.single = NULL,
1282+ .startup.single = timers_prepare_cpu,
12831283 .teardown.single = timers_dead_cpu,
12841284 },
12851285 /* Kicks the plugged cpu into life */
kernel/time/tick-sched.c+17−2
@@ -650,6 +650,11 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) · 649 unmodified lines
650650 ts->next_tick = 0;
651651 }
652652
653+static inline bool local_timer_softirq_pending(void)
654+{
655+ return local_softirq_pending() & TIMER_SOFTIRQ;
656+}
657+
653658 static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
654659 ktime_t now, int cpu)
655660 {
@@ -666,8 +671,18 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, · 10 unmodified lines
666671 } while (read_seqretry(&jiffies_lock, seq));
667672 ts->last_jiffies = basejiff;
668673
669− if (rcu_needs_cpu(basemono, &next_rcu) ||
670− arch_needs_cpu() || irq_work_needs_cpu()) {
674+ /*
675+ * Keep the periodic tick, when RCU, architecture or irq_work
676+ * requests it.
677+ * Aside of that check whether the local timer softirq is
678+ * pending. If so its a bad idea to call get_next_timer_interrupt()
679+ * because there is an already expired timer, so it will request
680+ * immeditate expiry, which rearms the hardware timer with a
681+ * minimal delta which brings us back to this place
682+ * immediately. Lather, rinse and repeat...
683+ */
684+ if (rcu_needs_cpu(basemono, &next_rcu) || arch_needs_cpu() ||
685+ irq_work_needs_cpu() || local_timer_softirq_pending()) {
671686 next_tick = basemono + TICK_NSEC;
672687 } else {
673688 /*
kernel/time/timer.c+24−11
@@ -823,11 +823,10 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) · 822 unmodified lines
823823 struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu);
824824
825825 /*
826− * If the timer is deferrable and nohz is active then we need to use
827− * the deferrable base.
826+ * If the timer is deferrable and NO_HZ_COMMON is set then we need
827+ * to use the deferrable base.
828828 */
829− if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active &&
830− (tflags & TIMER_DEFERRABLE))
829+ if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE))
831830 base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu);
832831 return base;
833832 }
@@ -837,11 +836,10 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) · 3 unmodified lines
837836 struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
838837
839838 /*
840− * If the timer is deferrable and nohz is active then we need to use
841− * the deferrable base.
839+ * If the timer is deferrable and NO_HZ_COMMON is set then we need
840+ * to use the deferrable base.
842841 */
843− if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active &&
844− (tflags & TIMER_DEFERRABLE))
842+ if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE))
845843 base = this_cpu_ptr(&timer_bases[BASE_DEF]);
846844 return base;
847845 }
@@ -1009,8 +1007,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option · 161 unmodified lines
10091007 if (!ret && (options & MOD_TIMER_PENDING_ONLY))
10101008 goto out_unlock;
10111009
1012− debug_activate(timer, expires);
1013−
10141010 new_base = get_target_base(base, timer->flags);
10151011
10161012 if (base != new_base) {
@@ -1034,6 +1030,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option · 17 unmodified lines
10341030 }
10351031 }
10361032
1033+ debug_activate(timer, expires);
1034+
10371035 timer->expires = expires;
10381036 /*
10391037 * If 'idx' was calculated above and the base time did not advance
@@ -1684,7 +1682,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) · 644 unmodified lines
16841682 base->must_forward_clk = false;
16851683
16861684 __run_timers(base);
1687− if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
1685+ if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
16881686 __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
16891687 }
16901688
@@ -1855,6 +1853,21 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h · 164 unmodified lines
18551853 }
18561854 }
18571855
1856+int timers_prepare_cpu(unsigned int cpu)
1857+{
1858+ struct timer_base *base;
1859+ int b;
1860+
1861+ for (b = 0; b < NR_BASES; b++) {
1862+ base = per_cpu_ptr(&timer_bases[b], cpu);
1863+ base->clk = jiffies;
1864+ base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
1865+ base->is_idle = false;
1866+ base->must_forward_clk = true;
1867+ }
1868+ return 0;
1869+}
1870+
18581871 int timers_dead_cpu(unsigned int cpu)
18591872 {
18601873 struct timer_base *old_base;
lib/timerqueue.c+5−3
@@ -33,8 +33,9 @@ · 32 unmodified lines
3333 * @head: head of timerqueue
3434 * @node: timer node to be added
3535 *
36− * Adds the timer node to the timerqueue, sorted by the
37− * node's expires value.
36+ * Adds the timer node to the timerqueue, sorted by the node's expires
37+ * value. Returns true if the newly added timer is the first expiring timer in
38+ * the queue.
3839 */
3940 bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)
4041 {
@@ -70,7 +71,8 @@ EXPORT_SYMBOL_GPL(timerqueue_add); · 29 unmodified lines
7071 * @head: head of timerqueue
7172 * @node: timer node to be removed
7273 *
73− * Removes the timer node from the timerqueue.
74+ * Removes the timer node from the timerqueue. Returns true if the queue is
75+ * not empty after the remove.
7476 */
7577 bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node)
7678 {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t