diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-31 15:30:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-31 15:30:34 -0500 |
commit | cea92e843e40452c08ba313abc39f59efbb4c29c (patch) | |
tree | 1c4352defd3a322e5b6efcafe3598bca698aaf5e /kernel/time/tick-sched.c | |
parent | 8d517bdfb57154b8a11d7f1682ecc0f79abf8e02 (diff) | |
parent | 9f4533cd7334235cd4c9b9fb1b0b8791e2ba01a7 (diff) |
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
Diffstat (limited to 'kernel/time/tick-sched.c')
-rw-r--r-- | kernel/time/tick-sched.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 77555faf6fbc..f7cc7abfcf25 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -650,6 +650,11 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) | |||
650 | ts->next_tick = 0; | 650 | ts->next_tick = 0; |
651 | } | 651 | } |
652 | 652 | ||
653 | static inline bool local_timer_softirq_pending(void) | ||
654 | { | ||
655 | return local_softirq_pending() & TIMER_SOFTIRQ; | ||
656 | } | ||
657 | |||
653 | static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, | 658 | static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, |
654 | ktime_t now, int cpu) | 659 | ktime_t now, int cpu) |
655 | { | 660 | { |
@@ -666,8 +671,18 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, | |||
666 | } while (read_seqretry(&jiffies_lock, seq)); | 671 | } while (read_seqretry(&jiffies_lock, seq)); |
667 | ts->last_jiffies = basejiff; | 672 | ts->last_jiffies = basejiff; |
668 | 673 | ||
669 | if (rcu_needs_cpu(basemono, &next_rcu) || | 674 | /* |
670 | arch_needs_cpu() || irq_work_needs_cpu()) { | 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()) { | ||
671 | next_tick = basemono + TICK_NSEC; | 686 | next_tick = basemono + TICK_NSEC; |
672 | } else { | 687 | } else { |
673 | /* | 688 | /* |