diff --git a/include/linux/timer.h b/include/linux/timer.h index e6789b8757d5..411d314bb274 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -198,6 +198,8 @@ extern void add_timer(struct timer_list *timer); extern int try_to_del_timer_sync(struct timer_list *timer); +extern struct timer_base timer_base_deferrable; + #ifdef CONFIG_SMP extern int del_timer_sync(struct timer_list *timer); #else diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 152a706ef8b8..72c07337f6b4 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -208,6 +208,7 @@ struct timer_base { } ____cacheline_aligned; static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]); +struct timer_base timer_base_deferrable; #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) unsigned int sysctl_timer_migration = 1; @@ -231,6 +232,9 @@ void timers_update_migration(bool update_nohz) per_cpu(timer_bases[BASE_DEF].nohz_active, cpu) = true; per_cpu(hrtimer_bases.nohz_active, cpu) = true; } + + timer_base_deferrable.migration_enabled = on; + timer_base_deferrable.nohz_active = true; } int timer_migration_handler(struct ctl_table *table, int write, @@ -817,8 +821,11 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) * the deferrable base. */ if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && - (tflags & TIMER_DEFERRABLE)) - base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); + (tflags & TIMER_DEFERRABLE)) { + base = &timer_base_deferrable; + if (tflags & TIMER_PINNED) + base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); + } return base; } @@ -832,7 +839,9 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) */ if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && (tflags & TIMER_DEFERRABLE)) - base = this_cpu_ptr(&timer_bases[BASE_DEF]); + base = &timer_base_deferrable; + if (tflags & TIMER_PINNED) + base = this_cpu_ptr(&timer_bases[BASE_DEF]); return base; } @@ -1612,8 +1621,10 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) { + __run_timers(&timer_base_deferrable); __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); + } } /*