diff --git a/kernel/softirq.c b/kernel/softirq.c index 77198911b8dd..4425d8dce44b 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -663,6 +663,13 @@ void irq_enter_rcu(void) { __irq_enter_raw(); + /* + * If this is a nested interrupt that hits the exit_to_user_mode_loop + * where it has enabled interrupts but before it has hit schedule() we + * could have hrtimers in an undefined state. Fix it up here. + */ + hrtimer_rearm_deferred(); + if (tick_nohz_full_cpu(smp_processor_id()) || (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))) tick_irq_enter(); @@ -719,8 +726,14 @@ static inline void __irq_exit_rcu(void) #endif account_hardirq_exit(current); preempt_count_sub(HARDIRQ_OFFSET); - if (!in_interrupt() && local_softirq_pending()) + if (!in_interrupt() && local_softirq_pending()) { + /* + * If we left hrtimers unarmed, make sure to arm them now, + * before enabling interrupts to run SoftIRQ. + */ + hrtimer_rearm_deferred(); invoke_softirq(); + } if (IS_ENABLED(CONFIG_IRQ_FORCED_THREADING) && force_irqthreads() && local_timers_pending_force_th() && !(in_nmi() | in_hardirq()))