summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/timers-Drop-expiry-lock-after-each-timer-invocation.patch
blob: 1a9f6a76f5e25dd143a2fb5a1fcfa0ca5a711675 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
Date: Thu, 10 Jan 2019 13:00:07 +0100
Subject: [PATCH] timers: Drop expiry lock after each timer invocation
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.2/older/patches-5.2.17-rt9.tar.xz

The ->expiry_lock lock is held until every timer is expired. So if a
__del_timer_sync() caller blocks on the lock then it has to wait until
every timer callback has completed.

Therefore drop the lock and acquire it after expiring the timer. To be
able to remove the timer, when it was expired, the running_timer struct
member has to be resetted to NULL as well. This happens after the timer
was expired. It is ok to do this lockless, because the only problem
could be that when a check is done too early, the old expired timer is
stored in there.

Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
[bigeasy: Patch description reworded]
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kernel/time/timer.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1384,10 +1384,16 @@ static void expire_timers(struct timer_b
 		if (timer->flags & TIMER_IRQSAFE) {
 			raw_spin_unlock(&base->lock);
 			call_timer_fn(timer, fn, baseclk);
+			base->running_timer = NULL;
+			spin_unlock(&base->expiry_lock);
+			spin_lock(&base->expiry_lock);
 			raw_spin_lock(&base->lock);
 		} else {
 			raw_spin_unlock_irq(&base->lock);
 			call_timer_fn(timer, fn, baseclk);
+			base->running_timer = NULL;
+			spin_unlock(&base->expiry_lock);
+			spin_lock(&base->expiry_lock);
 			raw_spin_lock_irq(&base->lock);
 		}
 	}
@@ -1709,7 +1715,6 @@ static inline void __run_timers(struct t
 		while (levels--)
 			expire_timers(base, heads + levels);
 	}
-	base->running_timer = NULL;
 	raw_spin_unlock_irq(&base->lock);
 	spin_unlock(&base->expiry_lock);
 }