All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE
@ 2020-11-03 19:09 Sebastian Andrzej Siewior
  2020-11-15 22:51 ` [tip: timers/core] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE timers tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 1 reply; 2+ messages in thread
From: Sebastian Andrzej Siewior @ 2020-11-03 19:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: Thomas Gleixner, John Stultz, Stephen Boyd, Mike Galbraith

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>
---
 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 7edc9fba34bbd..1e2403126ccfe 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1288,7 +1288,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);
 
 		/*
@@ -1372,6 +1372,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.29.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [tip: timers/core] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE timers
  2020-11-03 19:09 [PATCH] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE Sebastian Andrzej Siewior
@ 2020-11-15 22:51 ` tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 0 replies; 2+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2020-11-15 22:51 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Mike Galbraith, Sebastian Andrzej Siewior, Thomas Gleixner, x86,
	linux-kernel

The following commit has been merged into the timers/core branch of tip:

Commit-ID:     c725dafc95f1b37027840aaeaa8b7e4e9cd20516
Gitweb:        https://git.kernel.org/tip/c725dafc95f1b37027840aaeaa8b7e4e9cd20516
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 03 Nov 2020 20:09:37 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 15 Nov 2020 20:59:26 +01:00

timers: Don't block on ->expiry_lock for TIMER_IRQSAFE timers

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 livelock in
the case that the task waiting for the callback completion preempted the
callback.

This cannot be done for timers flagged with TIMER_IRQSAFE. These timers can
be canceled from an interrupt disabled context even on RT kernels.

The expiry callback of such timers is invoked with interrupts disabled so
there is no need to use the expiry lock mechanism because obviously the
callback cannot be preempted even on RT kernels.

Do not use the timer_base::expiry_lock mechanism when waiting for a running
callback to complete if the timer is flagged with TIMER_IRQSAFE.

Also add a lockdep assertion for RT kernels to validate that the expiry
lock mechanism is always invoked in preemptible context.

Reported-by: Mike Galbraith <efault@gmx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20201103190937.hga67rqhvknki3tp@linutronix.de

---
 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 de37e33..af9ddfb 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1288,7 +1288,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);
 
 		/*
@@ -1372,6 +1372,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);
 

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-11-15 22:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-03 19:09 [PATCH] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE Sebastian Andrzej Siewior
2020-11-15 22:51 ` [tip: timers/core] timers: Don't block on ->expiry_lock for TIMER_IRQSAFE timers tip-bot2 for Sebastian Andrzej Siewior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.