[PATCH net 09/10] mptcp: pm: avoid sleeping while holding rcu_read_lock
From: Matthieu Baerts (NGI0)
Date: Sun May 31 2026 - 23:14:20 EST
sk_stop_timer_sync() calls del_timer_sync(), which spin-waits for the
timer callback to complete on non-RT kernels. But on PREEMPT_RT, it can
sleep. Sleeping inside an RCU read-side critical section might trigger a
lockdep splat.
Instead, keep a reference to the timer, under rcu_read_lock, and call
sk_stop_timer*() without the RCU lock.
While at it, apply the reversed Xmas order when declaring variables.
Fixes: 426358d9be7c ("mptcp: fix a race in mptcp_pm_del_add_timer()")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Mat Martineau <martineau@xxxxxxxxxx>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@xxxxxxxxxx>
---
To: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
To: Clark Williams <clrkwllms@xxxxxxxxxx>
To: Steven Rostedt <rostedt@xxxxxxxxxxx>
To: Hannes Reinecke <hare@xxxxxxxxxx>
Cc: linux-rt-devel@xxxxxxxxxxxxxxx
---
net/mptcp/pm.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 3e770c7407e1..1e0866159972 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -401,9 +401,9 @@ struct mptcp_pm_add_entry *
mptcp_pm_del_add_timer(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr, bool check_id)
{
- struct mptcp_pm_add_entry *entry;
struct sock *sk = (struct sock *)msk;
- bool stop_timer = false;
+ struct mptcp_pm_add_entry *entry;
+ struct timer_list *timer = NULL;
rcu_read_lock();
@@ -411,7 +411,7 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
entry = mptcp_lookup_anno_list_by_saddr(msk, addr);
if (entry && (!check_id || entry->addr.id == addr->id)) {
entry->retrans_times = ADD_ADDR_RETRANS_MAX;
- stop_timer = true;
+ timer = &entry->add_timer;
}
if (!check_id && entry)
list_del(&entry->list);
@@ -420,14 +420,14 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
/* Note: entry might have been removed by another thread.
* We hold rcu_read_lock() to ensure it is not freed under us.
*/
- if (stop_timer) {
- if (check_id)
- sk_stop_timer(sk, &entry->add_timer);
- else
- sk_stop_timer_sync(sk, &entry->add_timer);
- }
+ if (timer && check_id)
+ sk_stop_timer(sk, timer);
rcu_read_unlock();
+
+ if (timer && !check_id)
+ sk_stop_timer_sync(sk, timer);
+
return entry;
}
--
2.53.0