[PATCH mptcp-next v4 5/7] mptcp: defer read_sock cleanup to mptcp_worker
Geliang Tang <[email protected]>
| Newsgroups | dev.linux.lists.mptcp |
|---|---|
| Message-ID | <874b60464d67b886f0425b79f75bd2919cc3ec46.1787295147.git.tanggeliang@kylinos.cn> |
From: Paolo Abeni <[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. The TLS path is not the only constraint: before the mptcp_recv_skb() calls, the TLS code would also reach __mptcp_read_sock(), which calls mptcp_rcv_space_adjust() and mptcp_cleanup_rbuf(). Both require holding the msk socket lock in process context, while the mptcp/TLS caller is in BH scope. Fix this by deferring sk->sk_data_ready(sk) to mptcp_worker() via a new MPTCP_WORK_READ_COMPLETE bit, reusing 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. Co-developed-by: Geliang Tang <[email protected]> Signed-off-by: Geliang Tang <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> --- net/mptcp/protocol.c | 25 +++++++++++++++++++------ net/mptcp/protocol.h | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a5caeb552869..d38c5eec5471 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3130,6 +3130,15 @@ static void mptcp_backlog_purge(struct sock *sk) sk_mem_reclaim(sk); } +static void mptcp_read_complete(struct sock *sk) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + + mptcp_cleanup_rbuf(msk, msk->read_copied); + mptcp_rcv_space_adjust(msk, msk->read_copied); + msk->read_copied = 0; +} + static void mptcp_do_fastclose(struct sock *sk) { struct mptcp_subflow_context *subflow, *tmp; @@ -3206,6 +3215,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_READ_COMPLETE, &msk->flags)) + mptcp_read_complete(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); @@ -4580,9 +4592,6 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off) struct sk_buff *skb; u32 offset; - if (!list_empty(&msk->backlog_list)) - mptcp_move_skbs(sk); - while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) { offset = (u32)msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { @@ -4597,6 +4606,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off) /* * Note: * - It is assumed that the socket was locked by the caller. + * - Can be invoked in BH scope. */ static int __mptcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor, bool noack) @@ -4638,11 +4648,14 @@ static int __mptcp_read_sock(struct sock *sk, read_descriptor_t *desc, if (noack) goto out; - mptcp_rcv_space_adjust(msk, copied); - + /* The backlog flushing is only needed when some data is actually + * moved and will take place in the workers's release callback. + */ if (copied > 0) { mptcp_recv_skb(sk, &offset); - mptcp_cleanup_rbuf(msk, copied); + msk->read_copied += copied; + set_bit(MPTCP_WORK_READ_COMPLETE, &msk->flags); + mptcp_schedule_work(sk); } out: return copied; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3a677a88ee4c..f08803593d66 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -117,6 +117,7 @@ #define MPTCP_FALLBACK_DONE 2 #define MPTCP_WORK_CLOSE_SUBFLOW 3 #define MPTCP_RTX_DISABLED 4 +#define MPTCP_WORK_READ_COMPLETE 5 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 @@ -312,6 +313,7 @@ struct mptcp_sock { u32 last_data_sent; u32 last_data_recv; u32 last_ack_recv; + int read_copied; unsigned long timer_ival; u32 token; u32 tfo_skb_len; -- 2.53.0