diff options
Diffstat (limited to 'debian/patches-rt/0067-timers-Don-t-block-on-expiry_lock-for-TIMER_IRQSAFE.patch')
-rw-r--r-- | debian/patches-rt/0067-timers-Don-t-block-on-expiry_lock-for-TIMER_IRQSAFE.patch | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/debian/patches-rt/0067-timers-Don-t-block-on-expiry_lock-for-TIMER_IRQSAFE.patch b/debian/patches-rt/0067-timers-Don-t-block-on-expiry_lock-for-TIMER_IRQSAFE.patch new file mode 100644 index 000000000..01c62e677 --- /dev/null +++ b/debian/patches-rt/0067-timers-Don-t-block-on-expiry_lock-for-TIMER_IRQSAFE.patch @@ -0,0 +1,60 @@ +From a7d720657001cb31fc09699861f12726418a4bf8 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Mon, 2 Nov 2020 14:14:24 +0100 +Subject: [PATCH 067/323] timers: Don't block on ->expiry_lock for + TIMER_IRQSAFE +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.204-rt100.tar.xz + +PREEMPT_RT does not spin and wait until a running timer completes its +callback but instead it blocks on a sleeping lock to prevent a deadlock. + +This blocking can not be done for workqueue's IRQ_SAFE timer which will +be canceled in an IRQ-off region. It has to happen to in IRQ-off region +because changing the PENDING bit and clearing the timer must not be +interrupted to avoid a busy-loop. + +The callback invocation of IRQSAFE timer is not preempted on PREEMPT_RT +so there is no need to synchronize on timer_base::expiry_lock. + +Don't acquire the timer_base::expiry_lock for TIMER_IRQSAFE flagged +timer. +Add a lockdep annotation to ensure that this function is always invoked +in preemptible context on PREEMPT_RT. + +Reported-by: Mike Galbraith <efault@gmx.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Cc: stable-rt@vger.kernel.org +--- + kernel/time/timer.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index e87e638c31bd..a4fdc7cfb723 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1287,7 +1287,7 @@ static void del_timer_wait_running(struct timer_list *timer) + u32 tf; + + tf = READ_ONCE(timer->flags); +- if (!(tf & TIMER_MIGRATING)) { ++ if (!(tf & (TIMER_MIGRATING | TIMER_IRQSAFE))) { + struct timer_base *base = get_timer_base(tf); + + /* +@@ -1371,6 +1371,13 @@ int del_timer_sync(struct timer_list *timer) + */ + WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); + ++ /* ++ * Must be able to sleep on PREEMPT_RT because of the slowpath in ++ * del_timer_wait_running(). ++ */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT) && !(timer->flags & TIMER_IRQSAFE)) ++ lockdep_assert_preemption_enabled(); ++ + do { + ret = try_to_del_timer_sync(timer); + +-- +2.43.0 + |