[PATCH mptcp-next 6/6] mptcp: defer sk_data_ready to the worker

Geliang Tang <[email protected]> Mon, 27 Jul 2026 19:29:21 +0800
Newsgroups dev.linux.lists.mptcp
Message-ID <5ab5630bc288d5af26ecacfcf29c7fe35f1fd670.1785150300.git.tanggeliang@kylinos.cn>
From: Geliang Tang <[email protected]>

When MPTCP carries TLS, the data path runs under mptcp_data_lock().
Reaching sk->sk_data_ready(sk) synchronously ends up at
tls_strp_check_rcv() -> mptcp_recv_skb() -> mptcp_move_skbs(), which
calls mptcp_data_lock() on the same sk and recurses on sk_lock.slock.

Fix this by deferring sk->sk_data_ready(sk) to mptcp_worker() via a
new MPTCP_WORK_DATA_READY bit, re-using the existing
mptcp_schedule_work()/mptcp_cancel_work() infrastructure. The wakeup
bit is consumed after the SOCK_DEAD && TCP_CLOSE destroy branch, so a
socket that reaches the destroy path drops the pending wakeup rather
than running it post-free.

No new work_struct, workqueue or cancel path is introduced; only a new
flag bit and the corresponding set_bit()/test_and_clear_bit() in the
mptcp_worker() body.

Signed-off-by: Geliang Tang <[email protected]>
---
 net/mptcp/protocol.c | 9 +++++++--
 net/mptcp/protocol.h | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 09b888ff33c7..be139718ed15 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1085,8 +1085,10 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
 	mptcp_rcv_rtt_update(msk, subflow);
 	if (!sock_owned_by_user(sk)) {
 		/* Wake-up the reader only for in-sequence data */
-		if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk))
-			sk->sk_data_ready(sk);
+		if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk)) {
+			set_bit(MPTCP_WORK_DATA_READY, &msk->flags);
+			mptcp_schedule_work(sk);
+		}
 	} else {
 		__mptcp_move_skbs_from_subflow(msk, ssk, false);
 	}
@@ -3223,6 +3225,9 @@ static void mptcp_worker(struct work_struct *work)
 	if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
 		__mptcp_retrans(sk);
 
+	if (test_and_clear_bit(MPTCP_WORK_DATA_READY, &msk->flags))
+		sk->sk_data_ready(sk);
+
 	fail_tout = msk->first ? READ_ONCE(mptcp_subflow_ctx(msk->first)->fail_tout) : 0;
 	if (fail_tout && time_after(jiffies, fail_tout))
 		mptcp_mp_fail_no_response(msk);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 8b16b0a4eb9f..7ba8b78ac6e4 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -115,6 +115,7 @@
 #define MPTCP_WORK_RTX		1
 #define MPTCP_FALLBACK_DONE	2
 #define MPTCP_WORK_CLOSE_SUBFLOW 3
+#define MPTCP_WORK_DATA_READY	4
 
 /* MPTCP socket release cb flags */
 #define MPTCP_PUSH_PENDING	1
-- 
2.53.0