On 2020-11-01 06:23:50 [+0100], Mike Galbraith wrote: > Apparently, timer ain't ever supposed to be running when you get there > via flush_delayed_work(), but it was. The first hunk will always trigger the warning and not just if the slow/wait path is really used. The second part should fix it. diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 7edc9fba34bbd..696bb88d15db2 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1372,6 +1372,13 @@ int del_timer_sync(struct timer_list *timer) */ WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); + /* + * Can not be used with disabled interrupts on PREEMPT_RT because + * del_timer_wait_running() sleeps. + */ + if (IS_ENABLED(CONFIG_PREEMPT_RT)) + WARN_ON(irqs_disabled()); + do { ret = try_to_del_timer_sync(timer); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c71da2a59e127..1ca03051a949f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3187,10 +3187,11 @@ EXPORT_SYMBOL_GPL(cancel_work_sync); */ bool flush_delayed_work(struct delayed_work *dwork) { - local_irq_disable(); - if (del_timer_sync(&dwork->timer)) + if (del_timer_sync(&dwork->timer)) { + local_irq_disable(); __queue_work(dwork->cpu, dwork->wq, &dwork->work); - local_irq_enable(); + local_irq_enable(); + } return flush_work(&dwork->work); } EXPORT_SYMBOL(flush_delayed_work); Sebastian