From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C78736DA03 for ; Mon, 27 Jul 2026 11:29:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151780; cv=none; b=MhsHXx8t+/ExdIH04BGiiTueqZxnGvLXESIksNkFSV/Ay7H6xPMf97fc0pJDcD/A5WAJIXZztQIIqQfMCY+/4jmJ56gYhW3ajGLZmSrGwylaUnpfgCQ2hy3mIlVa/LfolzT2r1AOp2D3xiyRj5Zb9dEqPL8fbLbV1gbBGYzTVJM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151780; c=relaxed/simple; bh=+9wUEVuFmXVcGt12WAv8ivqBqR0cd43RNcGLbNqk21E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=D5VRTEmJsmDPN+lcYrxgh84mXh4Wcw+9zvGuH8RI995pBgJ+6154XxC2nlb2DWXXa5f2XjQCFeyDR0XhgC3QRQYS1wHBkfHidWf8xjZ3uBxMCpQMK/u53d2TNl0uNYQjfKP/iJP+GyCAsFYv3wqkEm2d+5cB/cAEaBGgRw+thMw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RtBcFKgE; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RtBcFKgE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2885C1F00A3A; Mon, 27 Jul 2026 11:29:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151778; bh=PQP2kV++X3WWthtNvgVCKKl9o0iPA+bYwlnvQ0oQhh8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=RtBcFKgE0QjVpbH0hYT1DVp4FjCE9IlWxkzl3D4+ueonYz9Kem85ioLmNIDDPx15r e1cvH1JOqX0bjBop+lw+YRh0Ox9qFZsEDIIZhkxY6DtZGwaZ07C9D0EPrXBixLaFKQ zW8oz6Xm1xRX3CzwWqWwz74iOaXynjXi405bLWfsAhGfXBc3QoCnZj3dx3w9PSbNLm 8fWIs16kw6Jgm7+jBIchJknSAWU/twwrsGdJ/5CV3WNgw6fiwmjNpHUxC3DkxWysYJ BAohahLlOmDWWKI0iLX02JAMpU+g1DE7c0o+rGa2zbQXxg29agF1ZJTifYcaYGO+HX byzXc9i7u0CrA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni Subject: [PATCH mptcp-next 1/6] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Mon, 27 Jul 2026 19:29:16 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni It's used to save an additional comparison for in-order skbs, but is also a barrier to remove CB offset. Remove the helper, let __mptcp_try_coalesce() always perform the sequence check and remove duplicate checks from the callers. Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 954e20bb27de..d7838ab334fd 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -159,7 +159,8 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, { int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 - if (unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || + if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || + unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) @@ -192,15 +193,6 @@ static bool mptcp_try_coalesce(struct sock *sk, struct= sk_buff *to, return true; } =20 -static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff = *to, - struct sk_buff *from) -{ - if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq) - return false; - - return mptcp_try_coalesce((struct sock *)msk, to, from); -} - /* "inspired" by tcp_rcvbuf_grow(), main difference: * - mptcp does not maintain a msk-level window clamp * - returns true when the receive buffer is actually updated @@ -275,7 +267,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) /* with 2 subflows, adding at end of ooo queue is quite likely * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. */ - if (mptcp_ooo_try_coalesce(msk, msk->ooo_last_skb, skb)) { + if (mptcp_try_coalesce(sk, msk->ooo_last_skb, skb)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOMERGE); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUETAIL); return; @@ -321,7 +313,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); goto merge_right; } - } else if (mptcp_ooo_try_coalesce(msk, skb1, skb)) { + } else if (mptcp_try_coalesce(sk, skb1, skb)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOMERGE); return; } @@ -751,8 +743,7 @@ static void __mptcp_add_backlog(struct sock *sk, if (!list_empty(&msk->backlog_list)) tail =3D list_last_entry(&msk->backlog_list, struct sk_buff, list); =20 - if (tail && MPTCP_SKB_CB(skb)->map_seq =3D=3D MPTCP_SKB_CB(tail)->end_seq= && - ssk =3D=3D tail->sk && + if (tail && ssk =3D=3D tail->sk && __mptcp_try_coalesce(sk, tail, skb, &fragstolen, &delta)) { skb->truesize -=3D delta; kfree_skb_partial(skb, fragstolen); @@ -876,7 +867,7 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) =20 end_seq =3D MPTCP_SKB_CB(skb)->end_seq; tail =3D skb_peek_tail(&sk->sk_receive_queue); - if (!tail || !mptcp_ooo_try_coalesce(msk, tail, skb)) { + if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 /* skip overlapping data, if any */ --=20 2.53.0 From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1B6E636DA03 for ; Mon, 27 Jul 2026 11:29:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151782; cv=none; b=DYX5oLKkyR9yugSMC+BI9e+HspmfwSBjEaA6QIRTFOFN9T4XKqAVsBUZxaIM6vXKWT2bhVdf+/guUkoMBGKsHhUhzYqDYsodXekLsstPT0KFfuscSj5+4f+BaX59sE2sACG2lPtoQb9DCScmtFQxq1d2fkDCxc/EyRjzDgoolEo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151782; c=relaxed/simple; bh=4V7J6thEDQOE/FT2uXPu8udxRFB5WMjFbdlTYne4sh8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j82kK4PRl02u/drTloYB13+mtvZzTQAcYV5vMNKIotxCE4+kIB0Iwy7FFV928vc4fsAWtryhPAIDkw93PBRTWcdjbs5PxpFxV9hk8q0NUPotfEaU3KBqyW3ueK/IvGm7mXEMdZi8KhDZNFAv1Dqu2mnllcWT2cMXvp/XJ5QX9Yw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZInlfUV5; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZInlfUV5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F1A31F000E9; Mon, 27 Jul 2026 11:29:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151780; bh=XbEOd9aMOXzwQpuodgLuFSGN1U7XsWSCih4PlfDcK/Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZInlfUV5q7OygyBe8BAxRxTW4wMqWhZJDIvHUkXHpeq1ACctnw3whVVQUi+HrYrb/ MovKsnXffe2FKdT0fs9fiY515UUd8vLEimFciyga2Z5YZeWcXfoPTrRLhA1oQ69si0 jLfMWLtSDL4vPOA/8VirIgigeMR01M1hKo+d4QFcTZLNf7b3JaNwFAhTPwNcmSsgGi La1rrqoio8mTw6AxaSDwTetfL97R8wzNVe7DOF/uP2DhyjVMlOMAnRnYv0C+PM7xRB 2TqTMNXmXzlb4oewaMc9dfJOtdUd94UeDHNXmwR6PrJZiG8VIJZBflPeYuJwy21dp2 P57X4ECHfAOTw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni Subject: [PATCH mptcp-next 2/6] mptcp: drop the cant_coalesce CB field Date: Mon, 27 Jul 2026 19:29:17 +0800 Message-ID: <311dd7ed06e3e5cf600cafa747765d360f060b48.1785150300.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni Such field is used to ensure in-sequence processing in case of fastopen. Instead let's perform synchronization of the fastopen skb sequence when the IASN becomes available with the 3rd ack. When the `cant_coalesce` field has been introduced, commit f03afb3aeb9d ("mptcp: drop __mptcp_fastopen_gen_msk_ackseq()") noted that updating the already queued skb for passive fastopen socket at 3rd ack time would be difficult and race prone. The main point is that such update don't need to be synchronously performed at 3rd ack time, but is sufficient to perform it before the next segment is introduced into the msk. To such extent, add an explicit test in __mptcp_move_skb(). Performance wise this trades a conditional in the fast path - in __mptcp_try_coalesce() - with a similar one in __mptcp_move_skb() and a couple more in slow paths. After this change the user-space will always observe consistent sequence numbers in the receive queue, even in the TFO dummy mapping case. There is still a potential race in mptcp_inq_hint() that will be addressed by a later patch in the series. Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 2 +- net/mptcp/protocol.c | 28 ++++++++++++++++++++++++++-- net/mptcp/protocol.h | 4 +++- net/mptcp/subflow.c | 7 +++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index f717750906ff..d6895c2200cc 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -49,11 +49,11 @@ void mptcp_fastopen_subflow_synack_set_params(struct mp= tcp_subflow_context *subf MPTCP_SKB_CB(skb)->end_seq =3D 0; MPTCP_SKB_CB(skb)->offset =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce =3D 1; =20 mptcp_data_lock(sk); DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); =20 + mptcp_sk(sk)->rcvd_dummy_seq =3D true; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index d7838ab334fd..c0b6e312816f 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -160,7 +160,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || - unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) @@ -357,7 +356,6 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_= buff *skb, int offset, MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + copy_len; MPTCP_SKB_CB(skb)->offset =3D offset; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce =3D 0; =20 __skb_unlink(skb, &ssk->sk_receive_queue); =20 @@ -408,6 +406,24 @@ static bool mptcp_prune_ofo_queue(struct sock *sk, u64= seq) return mem <=3D sk->sk_rcvbuf; } =20 +void __mptcp_sync_rcv_sequence(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sk_buff *skb; + + if (likely(!msk->rcvd_dummy_seq)) + return; + + /* User space can have already received the TFO skb. */ + msk->rcvd_dummy_seq =3D false; + skb =3D skb_peek_tail(&sk->sk_receive_queue); + if (!skb) + return; + + MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -416,6 +432,12 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) =20 mptcp_borrow_fwdmem(sk, skb); =20 + /* Be sure to sync the eventual fastopen dummy mapping before any other + * skb lands into the msk. + */ + if (unlikely(msk->rcvd_dummy_seq)) + __mptcp_sync_rcv_sequence(sk); + /* Can't drop packets for fallback socket this late, or the stream * will break. */ @@ -3833,6 +3855,8 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + __mptcp_sync_rcv_sequence(sk); } } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index da40c6f3705f..19b6eafece71 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -124,13 +124,13 @@ #define MPTCP_FLUSH_JOIN_LIST 5 #define MPTCP_SYNC_STATE 6 #define MPTCP_SYNC_SNDBUF 7 +#define MPTCP_SYNC_SEQ 8 =20 struct mptcp_skb_cb { u64 map_seq; u64 end_seq; u32 offset; u8 has_rxtstamp; - u8 cant_coalesce; }; =20 #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) @@ -310,6 +310,7 @@ struct mptcp_sock { u32 token; unsigned long flags; unsigned long cb_flags; + bool rcvd_dummy_seq; bool recovery; /* closing subflow write queue reinjected */ bool can_ack; bool fully_established; @@ -1169,6 +1170,7 @@ void mptcp_event_pm_listener(const struct sock *ssk, enum mptcp_event_type event); bool mptcp_userspace_pm_active(const struct mptcp_sock *msk); =20 +void __mptcp_sync_rcv_sequence(struct sock *sk); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context= *subflow, struct request_sock *req); int mptcp_pm_genl_fill_addr(struct sk_buff *msg, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 8e386899ceb9..ea9b697c0300 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -478,6 +478,8 @@ static void subflow_set_remote_key(struct mptcp_sock *m= sk, struct mptcp_subflow_context *subflow, const struct mptcp_options_received *mp_opt) { + struct sock *sk =3D (struct sock *)msk; + /* active MPC subflow will reach here multiple times: * at subflow_finish_connect() time and at 4th ack time */ @@ -496,6 +498,11 @@ static void subflow_set_remote_key(struct mptcp_sock *= msk, WRITE_ONCE(msk->ack_seq, subflow->iasn); WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); + + if (!sock_owned_by_user(sk)) + __mptcp_sync_rcv_sequence(sk); + else + __set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, --=20 2.53.0 From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B6563F1AD7 for ; Mon, 27 Jul 2026 11:29:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151785; cv=none; b=CboBEfn54lbuTKzzD9pJFdIFeDI54Jwi55ozZjts8WfZesbT2XhW5PVdFZXTV8e7bs5GgQLw3T/aDSakPfSPm2vx48ziRY4viTfvTuL2MJ3ZRGn+wMdiMETWe6rJuOmajqhqlEOxBZT1dmcBdwqNQuVjIoS4onMN19eW3/YudZU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151785; c=relaxed/simple; bh=5CJ1/0MD3u0MLuQCYm8ovsGweo1qVKYdH0nYYRRDdZw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=syUdf10u0kqSUEwqcAMoFDmmY+3oAjc5jCUTzMqH/HHOAQ83/IDmQTVuUiPMQseDZKGIG8biTkVIGaO97CVaf2rILAjjCS4HKB/hT1IOX5AmrLIcTcOo5QaVSgMOF06zQU2LRFYKNp8oayu1hrPxQx44TFc4yMa87qoM3FaHoUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XGqxQ4ix; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XGqxQ4ix" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 594DE1F00A3A; Mon, 27 Jul 2026 11:29:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151783; bh=XAxelmmAJgWue2Vn+tYy+x6RF2FqXOvNRWSKehiJsWg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=XGqxQ4ixLCujCPHRLs64uy/XiOUIIeM0SaDKWNdpVfTcVgsYpEw7SwYzs6Q6JlZ2J TkRL2+KY6obxF1kuue6c7xg0BJjroriDjDyGMSDBURUApcGyTZ8Y5vUkdh2EdfgIoa XOFbuF0zQBB9ZgiD4uzc8qlHHcy28Dp6OgGOMD+uxM5YDvHjI6tfVfwUA2sGgE5F8Z pKk8HVgh+a7KZNOg651xgfVMvq9Xghdivvett++y6PHhUoeXZJBpuKEEZiTdgss2Et 8XGCQ4CWyu5MYkTxUkwMkzskuy9O1iark21IwhzeSL4yzp9oMI+nfofhEJzTSQqTJO 5VgItIrrHLSfA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni Subject: [PATCH mptcp-next 3/6] mptcp: remove CB offset field Date: Mon, 27 Jul 2026 19:29:18 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni Instead, use a new msk-level field to track the bytes already consumed inside each skb, carrying the amount of bytes already copied to user-space, alike what TCP is already doing. The newly introduce `copied_seq` field is always accessed under the msk socket lock, delegating the synchronization with IASN to the msk release CB, when the socket is owned by the user-space at remote key reception time. Such synchronization preserves any partial progress (copy) made on the TFO packet. Note that the explicit synchronization in __mptcp_move_skb() is needed to ensure that the TFO skb in the receive queue got its map_seq synched before the next skb lands into the receive queue when spooling the backlog at mptcp_release_cb() time, as the release CB synchronization will happen later. Prior to this patch, the TFO skb dummy mapping was always ignored, now it affects the `copied_seq` initial update: be sure to extends the sign correctly of such mapping initialization time. Overall this simplify a bit the __mptcp_recvmsg_mskq(), mptcp_inq_hint() and the __mptcp_move_skb() code and will also make possible the next patch. Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 15 ++++-- net/mptcp/protocol.c | 126 +++++++++++++++++++------------------------ net/mptcp/protocol.h | 8 ++- net/mptcp/subflow.c | 7 ++- 4 files changed, 77 insertions(+), 79 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index d6895c2200cc..421a50a85547 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -9,6 +9,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context= *subflow, struct request_sock *req) { + struct mptcp_sock *msk; struct sock *sk, *ssk; struct sk_buff *skb; struct tcp_sock *tp; @@ -44,20 +45,24 @@ void mptcp_fastopen_subflow_synack_set_params(struct mp= tcp_subflow_context *subf subflow->ssn_offset +=3D skb->len; has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; =20 - /* Only the sequence delta is relevant */ - MPTCP_SKB_CB(skb)->map_seq =3D -skb->len; + /* The TFO segment data sits before the IASN; before receiving + * the remote key, IASN is assumed being 0. + */ + MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; MPTCP_SKB_CB(skb)->end_seq =3D 0; - MPTCP_SKB_CB(skb)->offset =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); =20 - mptcp_sk(sk)->rcvd_dummy_seq =3D true; + msk =3D mptcp_sk(sk); + msk->rcvd_dummy_seq =3D true; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); - mptcp_sk(sk)->bytes_received +=3D skb->len; + msk->bytes_received +=3D skb->len; =20 sk->sk_data_ready(sk); =20 diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index c0b6e312816f..74a426bf6680 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -28,7 +28,7 @@ #include "protocol.h" #include "mib.h" =20 -static unsigned int mptcp_inq_hint(const struct sock *sk); +static unsigned int mptcp_inq_hint(struct sock *sk); =20 #define CREATE_TRACE_POINTS #include @@ -160,7 +160,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || - MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) return false; @@ -342,8 +341,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) skb_set_owner_r(skb, sk); } =20 -static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et, - int copy_len) +static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et) { struct mptcp_subflow_context *subflow =3D mptcp_subflow_ctx(ssk); bool has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; @@ -352,9 +350,9 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_= buff *skb, int offset, * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq * value */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow); - MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + copy_len; - MPTCP_SKB_CB(skb)->offset =3D offset; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -420,8 +418,8 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len; - MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) @@ -450,6 +448,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) } =20 if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { +add_queue: /* in sequence */ msk->bytes_received +=3D copy_len; WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); @@ -463,28 +462,18 @@ static bool __mptcp_move_skb(struct sock *sk, struct = sk_buff *skb) } else if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) { mptcp_data_queue_ofo(msk, skb); return false; - } + } else if (after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { + /* Partial packet: map_seq < ack_seq < end_seq. */ + int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 - /* Completely old data? */ - if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); - mptcp_drop(sk, skb); - return false; + copy_len -=3D delta; + goto add_queue; } =20 - /* Partial packet: map_seq < ack_seq < end_seq. - * Skip the already-acked bytes and enqueue the new data. - */ - copy_len =3D MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq; - MPTCP_SKB_CB(skb)->offset +=3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; - MPTCP_SKB_CB(skb)->map_seq +=3D msk->ack_seq - - MPTCP_SKB_CB(skb)->map_seq; - msk->bytes_received +=3D copy_len; - WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); - - skb_set_owner_r(skb, sk); - __skb_queue_tail(&sk->sk_receive_queue, skb); - return true; + /* Completely old data. */ + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); + mptcp_drop(sk, skb); + return false; } =20 static void mptcp_stop_rtx_timer(struct sock *sk) @@ -829,7 +818,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp= _sock *msk, if (offset < skb->len) { size_t len =3D skb->len - offset; =20 - mptcp_init_skb(ssk, skb, offset, len); + mptcp_init_skb(ssk, skb, offset); =20 if (own_msk) { mptcp_subflow_lend_fwdmem(subflow, skb); @@ -896,8 +885,6 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, delta); - MPTCP_SKB_CB(skb)->offset +=3D delta; - MPTCP_SKB_CB(skb)->map_seq +=3D delta; __skb_queue_tail(&sk->sk_receive_queue, skb); } msk->bytes_received +=3D end_seq - msk->ack_seq; @@ -2134,34 +2121,23 @@ static void mptcp_eat_recv_skb(struct sock *sk, str= uct sk_buff *skb) } =20 static int __mptcp_recvmsg_mskq(struct sock *sk, struct msghdr *msg, - size_t len, int flags, int copied_total, + size_t len, int flags, u64 *seq, struct scm_timestamping_internal *tss, int *cmsg_flags, struct sk_buff **last) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *skb, *tmp; - int total_data_len =3D 0; int copied =3D 0; =20 skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u32 delta, offset =3D MPTCP_SKB_CB(skb)->offset; + u64 offset =3D *seq - MPTCP_SKB_CB(skb)->map_seq; u32 data_len =3D skb->len - offset; u32 count; int err; =20 - if (flags & MSG_PEEK) { - /* skip already peeked skbs */ - if (total_data_len + data_len <=3D copied_total) { - total_data_len +=3D data_len; - *last =3D skb; - continue; - } - - /* skip the already peeked data in the current skb */ - delta =3D copied_total - total_data_len; - offset +=3D delta; - data_len -=3D delta; - } + /* Skip the already peeked data. */ + if (offset >=3D skb->len) + continue; =20 count =3D min_t(size_t, len - copied, data_len); if (!(flags & MSG_TRUNC)) { @@ -2179,14 +2155,12 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, st= ruct msghdr *msg, } =20 copied +=3D count; + *seq +=3D count; =20 if (!(flags & MSG_PEEK)) { msk->bytes_consumed +=3D count; - if (count < data_len) { - MPTCP_SKB_CB(skb)->offset +=3D count; - MPTCP_SKB_CB(skb)->map_seq +=3D count; + if (count < data_len) break; - } =20 mptcp_eat_recv_skb(sk, skb); } else { @@ -2339,25 +2313,23 @@ static bool mptcp_move_skbs(struct sock *sk) return enqueued; } =20 -static unsigned int mptcp_inq_hint(const struct sock *sk) +static unsigned int mptcp_inq_hint(struct sock *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); - const struct sk_buff *skb; - - skb =3D skb_peek(&sk->sk_receive_queue); - if (skb) { - u64 hint_val =3D READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq; + u64 hint_val; =20 - if (hint_val >=3D INT_MAX) - return INT_MAX; - - return (unsigned int)hint_val; - } + /* Avoid races vs ack_seq updates. */ + mptcp_data_lock(sk); + hint_val =3D msk->ack_seq - msk->copied_seq; + mptcp_data_unlock(sk); + if (hint_val >=3D INT_MAX) + return INT_MAX; =20 - if (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) + if (!hint_val && + (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN))) return 1; =20 - return 0; + return (unsigned int)hint_val; } =20 static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, @@ -2366,6 +2338,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, struct mptcp_sock *msk =3D mptcp_sk(sk); struct scm_timestamping_internal tss; int copied =3D 0, cmsg_flags =3D 0; + u64 peek_seq, *seq; int target; long timeo; =20 @@ -2385,6 +2358,11 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, =20 len =3D min_t(size_t, len, INT_MAX); target =3D sock_rcvlowat(sk, flags & MSG_WAITALL, len); + seq =3D &msk->copied_seq; + if (flags & MSG_PEEK) { + peek_seq =3D msk->copied_seq; + seq =3D &peek_seq; + } =20 if (unlikely(msk->recvmsg_inq)) cmsg_flags =3D MPTCP_CMSG_INQ; @@ -2394,7 +2372,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, int err, bytes_read; =20 bytes_read =3D __mptcp_recvmsg_mskq(sk, msg, len - copied, flags, - copied, &tss, &cmsg_flags, + seq, &tss, &cmsg_flags, &last); if (unlikely(bytes_read < 0)) { if (!copied) @@ -2449,6 +2427,10 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, err =3D copied ? : err; goto out_err; } + + /* Recompute peek offset after eventual seq resync. */ + if (flags & MSG_PEEK) + peek_seq =3D msk->copied_seq + copied; } =20 mptcp_cleanup_rbuf(msk, copied); @@ -3626,11 +3608,13 @@ static int mptcp_disconnect(struct sock *sk, int fl= ags) msk->bytes_retrans =3D 0; msk->rcvspace_init =3D 0; msk->fastclosing =3D 0; + msk->tfo_skb_len =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ WRITE_ONCE(msk->ack_seq, 0); atomic64_set(&msk->rcv_wnd_sent, 0); + msk->copied_seq =3D 0; =20 WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); @@ -3855,8 +3839,10 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); - if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + msk->copied_seq +=3D mptcp_iasn(msk); __mptcp_sync_rcv_sequence(sk); + } } } =20 @@ -4517,7 +4503,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk= , u32 *off) mptcp_move_skbs(sk); =20 while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { - offset =3D MPTCP_SKB_CB(skb)->offset; + offset =3D msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { *off =3D offset; return skb; @@ -4559,11 +4545,9 @@ static int __mptcp_read_sock(struct sock *sk, read_d= escriptor_t *desc, copied +=3D count; =20 msk->bytes_consumed +=3D count; - if (count < data_len) { - MPTCP_SKB_CB(skb)->offset +=3D count; - MPTCP_SKB_CB(skb)->map_seq +=3D count; + msk->copied_seq +=3D count; + if (count < data_len) break; - } =20 mptcp_eat_recv_skb(sk, skb); if (!desc->count) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 19b6eafece71..730af40ec9bc 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -129,7 +129,6 @@ struct mptcp_skb_cb { u64 map_seq; u64 end_seq; - u32 offset; u8 has_rxtstamp; }; =20 @@ -289,6 +288,7 @@ struct mptcp_sock { u64 bytes_sent; u64 snd_nxt; u64 bytes_received; + u64 copied_seq; u64 ack_seq; atomic64_t rcv_wnd_sent; u64 rcv_data_fin_seq; @@ -308,6 +308,7 @@ struct mptcp_sock { u32 last_ack_recv; unsigned long timer_ival; u32 token; + u32 tfo_skb_len; unsigned long flags; unsigned long cb_flags; bool rcvd_dummy_seq; @@ -860,6 +861,11 @@ struct sock *mptcp_subflow_get_retrans(struct mptcp_so= ck *msk); int mptcp_sched_get_send(struct mptcp_sock *msk); int mptcp_sched_get_retrans(struct mptcp_sock *msk); =20 +static inline u64 mptcp_iasn(const struct mptcp_sock *msk) +{ + return msk->ack_seq - msk->bytes_received + msk->tfo_skb_len; +} + static inline u64 mptcp_data_avail(const struct mptcp_sock *msk) { return READ_ONCE(msk->bytes_received) - READ_ONCE(msk->bytes_consumed); diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index ea9b697c0300..d0af5cb6f1b3 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -499,10 +499,13 @@ static void subflow_set_remote_key(struct mptcp_sock = *msk, WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); =20 - if (!sock_owned_by_user(sk)) + if (!sock_owned_by_user(sk)) { + /* User space could have already read partially the TFO skb */ + msk->copied_seq +=3D subflow->iasn; __mptcp_sync_rcv_sequence(sk); - else + } else { __set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); + } } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, --=20 2.53.0 From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A1B13F1AD7 for ; Mon, 27 Jul 2026 11:29:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151786; cv=none; b=HXO4zHxkCndNTLBfbEAYCkauf/DK8mWggypxY1+lsm6f4CJc5ds3HvL1aO/5TD+WSyl11qeYE/1pTVHr1u1t7JMRDReehIUWjKquxKtRTlAknDApazAXxfbK8Dy/ThTw6vD4i3ESkPvO95BFsPob97uQ1FsH2WE5FaVy8YT9Qdw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151786; c=relaxed/simple; bh=DopMhZwQg1nB+maRuxMYMabID+sw4ai3FRZXsLspimc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=G37DVTb+hWHOnzgOInqvVHsnHOJxTtt/DiF9n1S4pjAaWrXOBswL5A7ZxPiQsrzLJCq/QEad/iVvHlDlnUfpt73skaBTi3Chm3J9U49B48eQigDZuNeFRrzVFVcpBMoVHeHn3kTsIctGCAmgsq17LnG2N5H89CZEZXBScAVlr2g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Q60zcKlC; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Q60zcKlC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E53D61F000E9; Mon, 27 Jul 2026 11:29:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151785; bh=fIZaO6GDWm2pUJR3V4AVyta0Jxl6itb0MpGwkFPPJ+8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Q60zcKlCLQ6I5CrHicQq6r1XEOZDoeErTzoP3gtTi54qZ3dC/bWaTvxNDznQf7JlG GvUYBW7JDMtD29fw/IPhLNW5qqRsI4zN52ieFMArpovvA+XqFvAX9ENd+9H6jOpiwr YHprx+YdEEAA0wGN0tho3W1M+lzrhAazQiSy0NG5+ficUx0eGYXKcNVYOo2xUK5z83 KqjybPclCGW3gsTLjPCKlfIEtFyEqy2Nt97Q+Te/DNuhD/gu+8Y8u7U/9KphudLUWm KZVtk8J8zOVKs8Mh6IFjS6cYHeiGXtZezkEtbr7moykP6DHs2m+eB4OXH+GBl27FIg sZBFhyf34Eh2A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni Subject: [PATCH mptcp-next 4/6] mptcp: sync mptcp skb cb layout with tcp one Date: Mon, 27 Jul 2026 19:29:19 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni The MPTCP protocol uses a significantly different CB layout WRT TCP, as it includes different information and use 64 bits for the sequence numbers. As the msk-level rcvbuf buffer size is limited by the core socket code the INT_MAX; after validating the incoming skb vs the current receive window, we can safely use 32 bits for MPTCP-level sequence number. This allow updating the MPTCP CB layout so that fields with a corresponding TCP-level data use the same area inside the CB itself. Add build time check to ensure the latter invariant. Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 6 ++-- net/mptcp/protocol.c | 82 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 ++-- 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 421a50a85547..0d339dd454f9 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -48,8 +48,10 @@ void mptcp_fastopen_subflow_synack_set_params(struct mpt= cp_subflow_context *subf /* The TFO segment data sits before the IASN; before receiving * the remote key, IASN is assumed being 0. */ - MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D 0; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); @@ -57,7 +59,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf =20 msk =3D mptcp_sk(sk); msk->rcvd_dummy_seq =3D true; - msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq64; msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 74a426bf6680..b9e44c64c620 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -164,7 +164,7 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, !skb_try_coalesce(to, from, fragstolen, delta)) return false; =20 - pr_debug("colesced seq %llx into %llx new len %d new end seq %llx\n", + pr_debug("colesced seq %x into %x new len %d new end seq %x\n", MPTCP_SKB_CB(from)->map_seq, MPTCP_SKB_CB(to)->map_seq, to->len, MPTCP_SKB_CB(from)->end_seq); MPTCP_SKB_CB(to)->end_seq =3D MPTCP_SKB_CB(from)->end_seq; @@ -234,14 +234,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *m= sk, struct sk_buff *skb) { struct sock *sk =3D (struct sock *)msk; struct rb_node **p, *parent; - u64 seq, end_seq, max_seq; + u64 end_seq, max_seq; struct sk_buff *skb1; + u32 seq; =20 seq =3D MPTCP_SKB_CB(skb)->map_seq; - end_seq =3D MPTCP_SKB_CB(skb)->end_seq; + end_seq =3D MPTCP_SKB_CB(skb)->map_seq64 + skb->len; max_seq =3D atomic64_read(&msk->rcv_wnd_sent); =20 - pr_debug("msk=3D%p seq=3D%llx limit=3D%llx empty=3D%d\n", msk, seq, max_s= eq, + /* Use the full sequence space to perform the admission checks, to + * protect vs possible wrap-arounds. + */ + pr_debug("msk=3D%p seq=3D%x limit=3D%llx empty=3D%d\n", msk, seq, max_seq, RB_EMPTY_ROOT(&msk->out_of_order_queue)); if (after64(end_seq, max_seq)) { /* out of window */ @@ -272,7 +276,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) } =20 /* Can avoid an rbtree lookup if we are adding skb after ooo_last_skb */ - if (!before64(seq, MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq)) { + if (!before(seq, MPTCP_SKB_CB(msk->ooo_last_skb)->end_seq)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUETAIL); parent =3D &msk->ooo_last_skb->rbnode; p =3D &parent->rb_right; @@ -284,18 +288,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *m= sk, struct sk_buff *skb) while (*p) { parent =3D *p; skb1 =3D rb_to_skb(parent); - if (before64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->map_seq)) { p =3D &parent->rb_left; continue; } - if (before64(seq, MPTCP_SKB_CB(skb1)->end_seq)) { - if (!after64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (!after(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ mptcp_drop(sk, skb); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); return; } - if (after64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (after(seq, MPTCP_SKB_CB(skb1)->map_seq)) { /* partial overlap: * | skb | * | skb1 | @@ -326,7 +330,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) merge_right: /* Remove other segments covered by skb. */ while ((skb1 =3D skb_rb_next(skb)) !=3D NULL) { - if (before64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) + if (before((u32)end_seq, MPTCP_SKB_CB(skb1)->end_seq)) break; rb_erase(&skb1->rbnode, &msk->out_of_order_queue); mptcp_drop(sk, skb1); @@ -348,11 +352,13 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset) =20 /* the skb map_seq accounts for the skb offset: * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq - * value + * value; note that end seq number is only available in 32bits format. */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - - offset; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -418,13 +424,14 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { - u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; + u32 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *tail; =20 @@ -447,7 +454,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) return false; } =20 - if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { + if (MPTCP_SKB_CB(skb)->map_seq64 =3D=3D msk->ack_seq) { add_queue: /* in sequence */ msk->bytes_received +=3D copy_len; @@ -459,12 +466,13 @@ static bool __mptcp_move_skb(struct sock *sk, struct = sk_buff *skb) skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); return true; - } else if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) { + } else if (after64(MPTCP_SKB_CB(skb)->map_seq64, msk->ack_seq)) { mptcp_data_queue_ofo(msk, skb); return false; - } else if (after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { + } else if (after64(MPTCP_SKB_CB(skb)->map_seq64 + skb->len, + msk->ack_seq)) { /* Partial packet: map_seq < ack_seq < end_seq. */ - int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + int delta =3D (u32)msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 copy_len -=3D delta; goto add_queue; @@ -855,40 +863,40 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) { struct sock *sk =3D (struct sock *)msk; struct sk_buff *skb, *tail; + u32 seq_delta, ack_seq; bool moved =3D false; struct rb_node *p; - u64 end_seq; =20 p =3D rb_first(&msk->out_of_order_queue); pr_debug("msk=3D%p empty=3D%d\n", msk, RB_EMPTY_ROOT(&msk->out_of_order_q= ueue)); while (p) { + ack_seq =3D msk->ack_seq; skb =3D rb_to_skb(p); - if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) + if (after(MPTCP_SKB_CB(skb)->map_seq, ack_seq)) break; =20 p =3D rb_next(p); rb_erase(&skb->rbnode, &msk->out_of_order_queue); =20 - if (unlikely(!after64(MPTCP_SKB_CB(skb)->end_seq, - msk->ack_seq))) { + if (unlikely(!after(MPTCP_SKB_CB(skb)->end_seq, ack_seq))) { mptcp_drop(sk, skb); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); continue; } =20 - end_seq =3D MPTCP_SKB_CB(skb)->end_seq; + seq_delta =3D MPTCP_SKB_CB(skb)->end_seq - ack_seq; tail =3D skb_peek_tail(&sk->sk_receive_queue); if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { - int delta =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + int delta =3D ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 /* skip overlapping data, if any */ - pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", - MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, + pr_debug("uncoalesced seq=3D%x ack seq=3D%x delta=3D%d\n", + MPTCP_SKB_CB(skb)->map_seq, ack_seq, delta); __skb_queue_tail(&sk->sk_receive_queue, skb); } - msk->bytes_received +=3D end_seq - msk->ack_seq; - WRITE_ONCE(msk->ack_seq, end_seq); + msk->bytes_received +=3D seq_delta; + WRITE_ONCE(msk->ack_seq, msk->ack_seq + seq_delta); moved =3D true; } return moved; @@ -2130,7 +2138,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, stru= ct msghdr *msg, int copied =3D 0; =20 skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u64 offset =3D *seq - MPTCP_SKB_CB(skb)->map_seq; + u32 offset =3D (u32)(*seq) - MPTCP_SKB_CB(skb)->map_seq; u32 data_len =3D skb->len - offset; u32 count; int err; @@ -4503,7 +4511,7 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk= , u32 *off) mptcp_move_skbs(sk); =20 while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { - offset =3D msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; + offset =3D (u32)msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { *off =3D offset; return skb; @@ -4754,11 +4762,23 @@ static int mptcp_napi_poll(struct napi_struct *napi= , int budget) return work_done; } =20 +#define CHK_CB_FIELD(mptcp_field, tcp_field) \ + ({ \ + BUILD_BUG_ON(offsetof(struct mptcp_skb_cb, mptcp_field) !=3D \ + offsetof(struct tcp_skb_cb, tcp_field)); \ + BUILD_BUG_ON(offsetofend(struct mptcp_skb_cb, mptcp_field) !=3D \ + offsetofend(struct tcp_skb_cb, tcp_field)); \ + }) + void __init mptcp_proto_init(void) { struct mptcp_delegated_action *delegated; int cpu; =20 + CHK_CB_FIELD(map_seq, seq); + CHK_CB_FIELD(end_seq, end_seq); + CHK_CB_FIELD(flags, tcp_flags); + mptcp_prot.h.hashinfo =3D tcp_prot.h.hashinfo; =20 if (percpu_counter_init(&mptcp_sockets_allocated, 0, GFP_KERNEL)) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 730af40ec9bc..8b16b0a4eb9f 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -127,9 +127,12 @@ #define MPTCP_SYNC_SEQ 8 =20 struct mptcp_skb_cb { - u64 map_seq; - u64 end_seq; + u32 map_seq; + u32 end_seq; + u32 unused; + u16 flags; u8 has_rxtstamp; + u64 map_seq64; }; =20 #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) --=20 2.53.0 From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 972063FB067 for ; Mon, 27 Jul 2026 11:29:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151788; cv=none; b=JG5U91cnZUVX3ZTb8anfZ+4PKIHOoUlXZ1lWB3ujuNWWdedmp63XDTH+BUEv6KPWMshN21Z2rHDQiRPrkvwK0EtvxbdvK0H29IYHlN3Acbwt1mgTt3CLibLG+Z4LozzEqvi5YEYOYF4dOrbmFnES4V2OpYie4eXufE9z3bIvVBI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151788; c=relaxed/simple; bh=IiuCd/XadySPOkV69d9lrEmUQ0CtR/jUUFl6UKTKPOY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jyqjJ6FKPZWVY3/bg1zU6MJ0EUtgwlcL5KpDWgYYklo4VwEF4ksm5NADEwM8GLaQQH2N2AhCjJXHlWXrkHNpD6LpNfX1G6IIHif1pqhlqFtiYkBKYEDx8dQE9r82dJipGNE1t58LsZjn4R7zy+4gZ7YGK+qcO7gsqGleigpORZg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=im3c9RVB; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="im3c9RVB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4DDD1F00A3E; Mon, 27 Jul 2026 11:29:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151787; bh=jpXm/hJOvBXqROpamkMRhqcfbQbabC7Wd2Hxenf60Vw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=im3c9RVB2Csi13kyh+RW+izfVwpVrR+GWbf5YUwHTjBfpQkX8b/AYY1GQIQdFGOxB GawVC5AJIgbzjm8JNF/atNLd4HnpoQOUYR2r6VbuMJOtG8x8PNfWChfHzCheL1j7sk O2lHZReGx5i/9ryK6RDY0mEHGVV0df51p3ka06kFYMPpRcgnzQ3f/CqtolP9IA3lFX yVw3Z0HeQfojNwb3JhfGFNuP90y2rYqNEzgfdIm82R+W7z4MpP8der4wTGivaPBb8k MfDHIVfHjmcelnLBYUP0m6SpMvs9qs/jQFcO0vwmFwPe4XhROPHcUiCUCUI/sgr42Q wB4J3qo/CWNkA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next 5/6] mptcp: trim the duplicated skb head at receive enqueue Date: Mon, 27 Jul 2026 19:29:20 +0800 Message-ID: <81bd1e2fa9c959927bf0d1cae718a9da72164b5b.1785150300.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang After the CB offset field removal, the msk receive queue tracks the consumed position with the msk-level copied_seq and each skb map_seq points at its first byte (skb->data[0]). When the same DSN range is delivered more than once - a partially-acked segment, or duplicate data arriving on a second subflow - the skb is queued whole: its map_seq sits below msk->ack_seq and the duplicated bytes stay physically at the front of the skb. The linear readers (recvmsg, read_sock, read_done) cope with that by computing a per-skb offset =3D copied_seq - map_seq and skipping it. But consumers that treat the receive queue as a single contiguous byte stream cannot: the TLS strparser builds an anchor whose frag_list is the receive-queue skbs and reads it with a plain skb_copy_bits(), which has no per-skb offset knowledge. A record spanning such an skb boundary then reads the duplicated prefix and gets corrupted. Physically drop the duplicated leading bytes at enqueue time instead, so the receive queue is always contiguous. Add mptcp_trim_dup_head(), modelled on tcp_trim_head()/__pskb_trim_head() but tolerating a non-empty linear area: it pulls the linear head first, then eats the remaining bytes from the paged frags, and the caller bumps map_seq accordingly. The skb truesize is left unchanged on purpose - dropping only skb->len/data_len keeps the memory accounting over-reserved, hence always safe, at both callers and avoids any rmem/fwd_alloc fixup. Two callers trim the overlap: - __mptcp_move_skb() partial-packet branch (map_seq < ack_seq < end_seq). The skb is not owned yet, so on the -ENOMEM unclone failure refund the truesize borrowed by mptcp_borrow_fwdmem() before dropping it. - __mptcp_ofo_queue() uncoalesced branch. The skb is already msk owned, so mptcp_drop() refunds it; skip advancing ack_seq on failure. After trimming, map_seq equals the queue tail end_seq, so the segment can be coalesced normally. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 79 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index b9e44c64c620..09b888ff33c7 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -429,6 +430,62 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 +static int mptcp_trim_dup_head(struct sk_buff *skb, int delta) +{ + struct skb_shared_info *shinfo; + int headlen, eat, i, k; + + if (delta <=3D 0) + return 0; + + /* Received skbs are not expected to carry a frag_list; the frag loop + * below only handles the linear area and the paged frags. + */ + DEBUG_NET_WARN_ON_ONCE(skb_has_frag_list(skb)); + + if (skb_unclone_keeptruesize(skb, GFP_ATOMIC)) + return -ENOMEM; + + /* Eat the linear head first, then the paged frags. Note the skb + * truesize is left unchanged on purpose: dropping only skb->len / + * skb->data_len keeps the memory accounting over-reserved (hence + * always safe) at both callers. + */ + headlen =3D skb_headlen(skb); + eat =3D min(delta, headlen); + if (eat) { + __skb_pull(skb, eat); + delta -=3D eat; + } + if (!delta) + return 0; + + shinfo =3D skb_shinfo(skb); + eat =3D delta; + k =3D 0; + for (i =3D 0; i < shinfo->nr_frags; i++) { + int size =3D skb_frag_size(&shinfo->frags[i]); + + if (size <=3D eat) { + skb_frag_unref(skb, i); + eat -=3D size; + } else { + shinfo->frags[k] =3D shinfo->frags[i]; + if (eat) { + skb_frag_off_add(&shinfo->frags[k], eat); + skb_frag_size_sub(&shinfo->frags[k], eat); + eat =3D 0; + } + k++; + } + } + shinfo->nr_frags =3D k; + + skb->data_len -=3D delta; + skb->len -=3D delta; + return 0; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u32 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -474,6 +531,16 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) /* Partial packet: map_seq < ack_seq < end_seq. */ int delta =3D (u32)msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 + if (mptcp_trim_dup_head(skb, delta)) { + /* skb is not owned yet: mptcp_borrow_fwdmem() added its + * truesize to sk_forward_alloc and cleared skb->sk, so + * mptcp_drop() won't refund it. Do it here. + */ + sk_forward_alloc_add(sk, -skb->truesize); + mptcp_drop(sk, skb); + return false; + } + MPTCP_SKB_CB(skb)->map_seq +=3D delta; copy_len -=3D delta; goto add_queue; } @@ -889,10 +956,20 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) if (!tail || !mptcp_try_coalesce(sk, tail, skb)) { int delta =3D ack_seq - MPTCP_SKB_CB(skb)->map_seq; =20 - /* skip overlapping data, if any */ + /* Physically trim the overlapping prefix, if any, + * so the receive queue stays contiguous. + */ pr_debug("uncoalesced seq=3D%x ack seq=3D%x delta=3D%d\n", MPTCP_SKB_CB(skb)->map_seq, ack_seq, delta); + if (mptcp_trim_dup_head(skb, delta)) { + /* skb is msk-owned here; mptcp_drop() refunds + * it. Skip advancing ack_seq/bytes_received. + */ + mptcp_drop(sk, skb); + continue; + } + MPTCP_SKB_CB(skb)->map_seq +=3D delta; __skb_queue_tail(&sk->sk_receive_queue, skb); } msk->bytes_received +=3D seq_delta; --=20 2.53.0 From nobody Mon Aug 24 20:41:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46C0C3F1AD7 for ; Mon, 27 Jul 2026 11:29:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151790; cv=none; b=tPtMnQfwbl6eK9A9xGfkgeAuaNU7EcRnLQ73bkh6FIKR67pPX7NKhfiOPKrM08eiSZt1WdTvOOcDR9g3qScbEgiFz9B8grdWMlapm05DsiWxmdsCbnK+cfV66IBQVmOQodFP8/rNWvg6J0F3nU2Ng4enmE8MTbgPFttKQ3sOuOk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785151790; c=relaxed/simple; bh=vRoXiBR4d/+nWQBWjFeIDTZY5GiuYbnWMuE7lyAlz0A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P0pWSpiuAh7IHWIYA6nSuhGasQY2LNMgltTJEkhPqmtKIwpv+GW0VFPOlacrJc2g5BL8rBpuXbDCOeU44LnTpeKaNbU75EEAX7q5bYIZcD7TyOgqdqPA3NWpToFVkwhPBKHS8NOX0F9BUjUfScReIlRLLKDYmKDDfW9hnlOY1Ts= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=E1dsI0Rr; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="E1dsI0Rr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E0BCC1F000E9; Mon, 27 Jul 2026 11:29:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785151788; bh=7hJ5GPi815MX/iylDVo0keGB06RD65fz8uydIxo/qSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=E1dsI0RrJ1mcWDDJ91sSiTF04KIHNtNQ6ElzGuJRckYbOq0gN/wxkjOjgRmJY1vuI Ozu46/jnHdNzQ9SEt75PskLyeGk9poZ96HVHSE7Ws3beYTIiZ1O7UxIMVaX+IICEFv rPCifUV0OVxSE6EDwfZaDK4KKnE6YaOuL/J3oSqCMSqV7UXcxUg/f1qf2ZnGrsnxyJ 8gbFkUroa+pZN81AMVpUVjDgT/v/UEVkxTp2ni14RRGlQfRvXxoWl44gyfLjy4e8Oa zI/hpIyWHtxMi7MeEdbHWUOsRYEy9by6+6CZ5Vpl7cDTicT2hYeVFrLIyUytuqMBuZ hYSRmUmC4Wjzw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next 6/6] mptcp: defer sk_data_ready to the worker Date: Mon, 27 Jul 2026 19:29:21 +0800 Message-ID: <5ab5630bc288d5af26ecacfcf29c7fe35f1fd670.1785150300.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang 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 --- 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); =20 + if (test_and_clear_bit(MPTCP_WORK_DATA_READY, &msk->flags)) + sk->sk_data_ready(sk); + fail_tout =3D 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 =20 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 --=20 2.53.0