diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 290345a0b6051fe617fb825ba56b72531fe51f00..542b4fa2cda9b0051d9a6fe11a7d642e2d2bbc59 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -508,9 +508,9 @@ extern void sysrq_timer_list_show(void); int hrtimers_prepare_cpu(unsigned int cpu); #ifdef CONFIG_HOTPLUG_CPU -int hrtimers_cpu_dying(unsigned int cpu); +int hrtimers_dead_cpu(unsigned int cpu); #else -static inline int hrtimers_cpu_dying(unsigned int cpu) { return 0; } +#define hrtimers_dead_cpu NULL #endif #endif diff --git a/include/linux/smp.h b/include/linux/smp.h index 634659d48a5fe35c51b5d4f5f60f1445c45de1fa..9fb239e12b82485b5c14d4fd21a9db650b3bdce9 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -220,6 +220,5 @@ int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, int smpcfd_prepare_cpu(unsigned int cpu); int smpcfd_dead_cpu(unsigned int cpu); int smpcfd_dying_cpu(unsigned int cpu); -int smpcfd_and_hrtimer_dying_cpu(unsigned int cpu); #endif /* __LINUX_SMP_H */ diff --git a/kernel/cpu.c b/kernel/cpu.c index cfed9b994e62c4f2aa177f284652ac8e7de2af34..c943454b748eecdbbc3e5fbd557b9ea0319dfaff 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1390,7 +1390,7 @@ static struct cpuhp_step cpuhp_hp_states[] = { [CPUHP_HRTIMERS_PREPARE] = { .name = "hrtimers:prepare", .startup.single = hrtimers_prepare_cpu, - .teardown.single = NULL, + .teardown.single = hrtimers_dead_cpu, }, [CPUHP_SMPCFD_PREPARE] = { .name = "smpcfd:prepare", @@ -1452,24 +1452,11 @@ static struct cpuhp_step cpuhp_hp_states[] = { .startup.single = NULL, .teardown.single = rcutree_dying_cpu, }, - /* - * In order to fix the kabi breakage, we had to move the hrtimers:dying - * step into smpcfd:dying and create a new function smpcfd_and_hrtimer_dying_cpu(). - * Please ensure that there are no other steps with teardown handler - * between smpcfd:dying and cpu:teardown. - */ [CPUHP_AP_SMPCFD_DYING] = { .name = "smpcfd:dying", .startup.single = NULL, - .teardown.single = smpcfd_and_hrtimer_dying_cpu, + .teardown.single = smpcfd_dying_cpu, }, - - /* - * Attention: Please do not add steps between smpcfd:dying - * and ap:online. Please refer to the above for specific - * reasons. - */ - /* Entry state on starting. Interrupts enabled from here on. Transient * state for synchronsization */ [CPUHP_AP_ONLINE] = { diff --git a/kernel/smp.c b/kernel/smp.c index 979b3b13e741db3affd9980473397901ab279550..be15d3a579548464ea49e9ca58ffb7ff04d4f353 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -71,14 +71,6 @@ int smpcfd_dead_cpu(unsigned int cpu) return 0; } -int smpcfd_and_hrtimer_dying_cpu(unsigned int cpu) -{ - hrtimers_cpu_dying(cpu); - smpcfd_dying_cpu(cpu); - - return 0; -} - int smpcfd_dying_cpu(unsigned int cpu) { /* diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index bf74f43e42af0490154d49a9bc51aa0543f5ded1..8512f06f0ebef5db9e8ebef647cced3f3e511fdf 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1922,22 +1922,29 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, } } -int hrtimers_cpu_dying(unsigned int dying_cpu) +int hrtimers_dead_cpu(unsigned int scpu) { struct hrtimer_cpu_base *old_base, *new_base; - int i, ncpu = cpumask_first(cpu_active_mask); - - tick_cancel_sched_timer(dying_cpu); + int i; - old_base = this_cpu_ptr(&hrtimer_bases); - new_base = &per_cpu(hrtimer_bases, ncpu); + BUG_ON(cpu_online(scpu)); + tick_cancel_sched_timer(scpu); + /* + * this BH disable ensures that raise_softirq_irqoff() does + * not wakeup ksoftirqd (and acquire the pi-lock) while + * holding the cpu_base lock + */ + local_bh_disable(); + local_irq_disable(); + old_base = &per_cpu(hrtimer_bases, scpu); + new_base = this_cpu_ptr(&hrtimer_bases); /* * The caller is globally serialized and nobody else * takes two locks at once, deadlock is not possible. */ - raw_spin_lock(&old_base->lock); - raw_spin_lock_nested(&new_base->lock, SINGLE_DEPTH_NESTING); + raw_spin_lock(&new_base->lock); + raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { migrate_hrtimer_list(&old_base->clock_base[i], @@ -1948,13 +1955,15 @@ int hrtimers_cpu_dying(unsigned int dying_cpu) * The migration might have changed the first expiring softirq * timer on this CPU. Update it. */ - __hrtimer_get_next_event(new_base, HRTIMER_ACTIVE_SOFT); - /* Tell the other CPU to retrigger the next event */ - smp_call_function_single(ncpu, retrigger_next_event, NULL, 0); + hrtimer_update_softirq_timer(new_base, false); - raw_spin_unlock(&new_base->lock); raw_spin_unlock(&old_base->lock); + raw_spin_unlock(&new_base->lock); + /* Check, if we got expired work to do */ + __hrtimer_peek_ahead_timers(); + local_irq_enable(); + local_bh_enable(); return 0; }