From nobody Thu Nov 5 07:28:00 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793349704; b=nFMOHoqUIQ3YejWjsh/62bSFcLrtd+eCP/ihursJOzZNGQ9UXrjWF3AyqF0uglqJKiXG RyV1Nr1rFgl349GeGuCusMlewWh2OxkgLzpuQ0RWVdSJ2aWxNuZLil+Kpj3Aitk8nhW49 DJGhC0s16924anDEH2aTA/mxxG+ys+qP8t7oZplZcIN/swVtU8PlJhStZwPVqkJH409bO N+TXeEWWzfm/0Ynq+zcygcO/Po9UlTRHxmMR7n+Ngja8lrJVb1lcMLLbr03izjuxc2cYY 1yPHorhCVV8rVc64t28pqRRQ6SOMw8sdriQ24baMoUbqCwuh6qR2e1csn7qo7Hn75IA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793349704; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=1J8C7pphSK2zVga48ZXLypGHUwLsv9JZ0n5GsGZOvyg=; b=5XbTnNiAZzE2gjX2OtMasmPg2oOx+InEDl0989DnfmfpoSSDzCqer7ksRAvadV1uGTuk NLIE/RWtvJ/PmorESRL+1mr6H1y4n1jt9ER1r5dglH4KfjQEZ1puCzzIL2gVDXm7jmQN7 yUTWwxwFNPo1obyCefUdyZWCQ0cX/ovMk1pnecLbvezE3+9RiYuzIVnbrqJdrhQOMocvz vqe0RI+COmyzdHhnqwOXBH0K4+NVyrtrz1y7oUBMW/DNtbgBVhqiVJFbK6s9jhGUyXNyN wFERVygpdrT4kqjKD83G2R2QUFL4hUXE5Wz9EqaVzyyX/I152Fb/tzrD0KpfYIe/mBA== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=SPp5olNV; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2DE7D606A31A for ; Fri, 30 Oct 2026 08:41:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=SPp5olNV Received: by smtp.kernel.org (Postfix) with ESMTPSA id 53A001F0093A; Fri, 30 Oct 2026 08:41:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793349703; bh=1J8C7pphSK2zVga48ZXLypGHUwLsv9JZ0n5GsGZOvyg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=SPp5olNVgIQn8SQ2ONiZzuzW08zGOfUP+qa1JGfh4vIvSsInan2mfcSSkY3ShqaO3 Z8dvaHc239FAPL1O4BuorNpaRpvgBAREBarI3vX6r9LAFF6yKAZLQlN61i+3VqPRdb 4Ro2zAMYBguQn8dUCbz8mgEIRxYb7EV+6Uk84ds3bKQYdcWK7BW5st/T3/tbXMFY3Y 3ebDF+W2WD8kIgM79N3c/v4mEK8qZY45DlSmVfzIzaOkx8H+8AiicaVmikJsk+XCPk d2xFri/ft2UDoXTUvFVOMcrlunHZaraqTZ1sKybJnI4enrYQR6Evp4VSCydUZazLqi Hr1w+dNAHMDLw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v18 1/5] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Fri, 30 Oct 2026 16:41:22 +0800 Message-ID: <2d215e3e2e2dd8d339239043810610a2618d31d6.1793349369.git.geliang@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list 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. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang 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 02a4f479d9d8..528a72da646c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -167,7 +167,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)) @@ -200,15 +201,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 @@ -348,7 +340,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; @@ -394,7 +386,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; } @@ -777,8 +769,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); @@ -902,7 +893,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.55.0 From nobody Thu Nov 5 07:28:00 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793349705; b=HkFww/wlImuy6t1+TF/Am37WepvnonGrAxloy1qDTMzs4gjo/1+7EQZyP7VBMjvsKyPT stAM0RNJhbrXm3hfijQYxxPxUxHqPsfdyfcQw/WdPLMZO/MlXVh65EbDlE0Zl/TR3FFQs gzK1otyf8+UU8ffDrQRMtcYz9hl+UCmW5q7Gg6DgQwW5XcKjXSw3cz/KY4+nBET19OA9h mxeRy9wh5DxSYeytHitUw6vR5B7HRTyvqJ1Ly8p2OQ48mG0ROJ+G4nQYytazpA1pp30zj uCL1m21bJ0hCr+DRIU9y7lH9XriPCgqeiCIlVozUPGfGxIyISsXoH8SOLUq0Z0I63Lg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793349705; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=8LXNcJyM5cQ19Ulzi5NmNfox6j6IGp/S2KY26EFzZ3M=; b=R9j2ee8wARqyTTCXXVsmkvk55x7YpnEHyB2XnkpZ6jDQRqK7hRivMunbd4umtgF8YcLH ehB1Tgckbu+pJydDPmT+KRA40ZjfiWQWZ08uLxwO+yAll5TQARevfWsnbVKMjXEedeev4 wmzi9BzUnzDmnzEwyHcqzxmPX1lorXOWcpDCjbom/PzDXvUKw+L8rMmxltEQwEuM1Yvs1 lzVtpVJsmxvtWjq77dC9kc8gTgCMUkZiUfgOKDOluOlCZmTwD0p3SBoEw/DuARhQIAGC8 ZxjHZzTWFfyi5pNhNvPUT3/w86YvZlXEgBaDUKHCJBGY66tDFR+jqpj4smR/I5wVMog== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=VC7750xK; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98B2F606A31D for ; Fri, 30 Oct 2026 08:41:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=VC7750xK Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5C2631F000C1; Fri, 30 Oct 2026 08:41:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793349705; bh=8LXNcJyM5cQ19Ulzi5NmNfox6j6IGp/S2KY26EFzZ3M=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=VC7750xKxlpUbZBddwHaP5gaoxHAzYgNrWPgVD06Z6bdyym0XBp4J6EeRQZHPWmCj Pf5ETHehiWx9a2m/LB7sSk6HVG1h/NxQAxM4yo7314N6HwkJKDJF7eZWOF275nF92y gMCLdZzy8fr52axQw2kNgMu+Dik/88YgA1ZoYnsktCOduYBIHj7rKSGciNSWKT3jjb fuYwbVFi0z7uKixEWOuAoWEHJ01NPq5+9xvd7Uy79/pfEeRHeCMxDZlsC2ZyBEdspA g7oMM0gItuNs8pZK85g2uXYhlhkpRHwCwssql8aYkc2ckUdJTSH8acIjgDuQavDcBT Nj5pGclIUQZvA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v18 2/5] mptcp: drop the cant_coalesce CB field Date: Fri, 30 Oct 2026 16:41:23 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list 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. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 6 ++++-- net/mptcp/protocol.c | 31 +++++++++++++++++++++++++++++-- net/mptcp/protocol.h | 4 +++- net/mptcp/subflow.c | 7 +++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index f717750906ff..e18b31028e7e 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; @@ -49,15 +50,16 @@ 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 + msk =3D mptcp_sk(sk); + msk->rcvd_dummy_seq =3D true; 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 528a72da646c..fe154b181683 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -168,7 +168,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)) @@ -430,7 +429,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 @@ -438,6 +436,26 @@ static void mptcp_init_skb(struct sock *ssk, struct sk= _buff *skb, int offset, skb_dst_drop(skb); } =20 +void __mptcp_sync_rcv_sequence(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sk_buff *skb; + u32 offset; + + 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; + + offset =3D MPTCP_SKB_CB(skb)->offset; + MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len + offset; + 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; @@ -446,6 +464,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); + if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { /* in sequence */ insert: @@ -3680,6 +3704,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) msk->bytes_retrans =3D 0; msk->rcvspace_init =3D 0; msk->fastclosing =3D 0; + msk->rcvd_dummy_seq =3D false; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -3930,6 +3955,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 3be60da12924..c317d8b59fff 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -126,13 +126,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])) @@ -336,6 +336,7 @@ struct mptcp_sock { bool use_64bit_ack; /* Set when we received a 64-bit DSN */ bool csum_enabled; bool allow_infinite_fallback; + bool rcvd_dummy_seq; u8 pending_state; /* A subflow asked to set this sk_state, * protected by the msk data lock */ @@ -1193,6 +1194,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 78e886b20258..49a000b8dcb8 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -515,6 +515,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 */ @@ -533,6 +535,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.55.0 From nobody Thu Nov 5 07:28:00 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793349707; b=4ClC5HJLAvzVhDa9kZCuXM3W4fMJ2UxSvGeLLGPec3Dnh9SO2z4N+X+H469KXveNhKsi VywYGZpHNQXBMAR5a9PDHu7VLFXOMv2SvKdq5P4gdoWwWjUatMt+P13+p519iicDguh0v wu1u6H201fd7Nk39FU0s+MHLamV894qb4Gtjo+0pAoo0Y66y5x85kHJd06wi9WW98wijA x5wLGJvnC4K1ZBLYFXrNXG76NS+M1gtutPZEkvh7alST8kR73vGcZo6hEC/XmrBP6ys/D 6/R87lnRLLsCPWOJArR4iM5e3k3Oaft4Jr8+y4lr6D9fFsqFYn1c4HB/z2EReccm7TA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793349707; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=mVJORKmw4g1XtMxbfQlXi+f86tDD5++yCbYykJIXZg8=; b=zR9qXzE2/dN/ZxjliNt22T7rz+b+1mEr/TkFSoYjmvemirGeD52fvSKv0KPmM6Chr15Z dF2cX3dZI6S6uBXr+kIisFhpD1bZCoL3ZXeNKD7iJE6cFUMYtiTrfBlxu3wdNsz/a5G6g iBAtBxknp5hpHVj4Q/KzxrDR76e/EwZm63bv+txu1exD8u5tbUAsOvvCH2ck1MO5B+cpy a58Do0xV05vC9dfkeWfPslE9xBe+W9Zt5DgL+6iwxvcDxYRRIlqibUsCTRykDC703BNY9 yebo0Faw/nXdcvwrTMWkoOpJGxzhKNmZZj+ZlxIwTeStoOJTP7iYykXwulk1O+1/VZw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=kLVdCOkX; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 264C1606A31A for ; Fri, 30 Oct 2026 08:41:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=kLVdCOkX Received: by smtp.kernel.org (Postfix) with ESMTPSA id 089CB1F000C1; Fri, 30 Oct 2026 08:41:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793349707; bh=mVJORKmw4g1XtMxbfQlXi+f86tDD5++yCbYykJIXZg8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kLVdCOkXbhUizj+yf2RQBnRjRSAQBfyBjx2zycmjZyWig3D99egGehVJlBRalxVRm lAun6VXrNtKRaqEIQrru/gpZrZuZeduOjOFyyqmCtpXm5NX8DSIgSo/mZrADvXHKe0 ro5bGTb6faCSCjPHpNJxanYRtQwLdpunRaInMscni21l+tKvTl/smVIJYJSswYKC5r E+XtwAVNrB1Y4XGe2ehzMAwGPbbt9ARh86HOcGYik4Utx08isknZs5l2WZhoO2KnnJ vV0OQpqi5qibVy4V4mlOQlz6DpNApEHAo9gcA28GneRtbIGSPW6mFFkMgrvNafajc+ dtdSpg09B3oug== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v18 3/5] mptcp: remove CB offset field Date: Fri, 30 Oct 2026 16:41:24 +0800 Message-ID: <3cc892c20ed48f8f31f40e7a9ff7363d4b7b0806.1793349369.git.geliang@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list 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 (map_seq =3D -(u32)skb->len, zero-extended to u64) caused mptcp_inq_hint() to compute a wrapped ack_seq - map_seq, so SIOCINQ and TCP_CM_INQ returned INT_MAX before the MPC ACK. This patch fixes that behaviour through both the -(u64)skb->len sign fix and the new ack_seq - copied_seq hint. Overall this simplifies a bit the __mptcp_recvmsg_mskq(), mptcp_inq_hint() and the __mptcp_move_skb() code and will also make possible the next patch. Initialize MPTCP sequence space to 0 in mptcp_propagate_state() when mp_opt is NULL, ensuring SKB's map_seq starts from 0 to match msk->copied_seq and prevent offset calculation underflow in fallback mode. The writes are safe without sock_owned_by_user() deferral because mptcp_propagate_state() already holds mptcp_data_lock(). Note: mptcp_iasn() assumes ack_seq and bytes_received advance in lockstep. If mptcp_check_data_fin() increments ack_seq for a DATA_FIN before the deferred SYNC_SEQ sync runs, copied_seq ends up one byte past the real IASN. In practice this requires a DATA_FIN to arrive before the MPC third ACK on a passive TFO socket, which cannot happen because the connection is not yet established. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 9 ++-- net/mptcp/protocol.c | 102 +++++++++++++++++++------------------------ net/mptcp/protocol.h | 8 +++- net/mptcp/subflow.c | 15 +++++-- 4 files changed, 70 insertions(+), 64 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index e18b31028e7e..421a50a85547 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -45,10 +45,11 @@ 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); @@ -56,6 +57,8 @@ 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->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); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index fe154b181683..792147b5279f 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -168,7 +168,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; @@ -415,8 +414,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; @@ -425,9 +423,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); @@ -440,7 +438,6 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *skb; - u32 offset; =20 if (likely(!msk->rcvd_dummy_seq)) return; @@ -451,9 +448,8 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - offset =3D MPTCP_SKB_CB(skb)->offset; - MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len + offset; - 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) @@ -496,10 +492,6 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) /* Partial packet */ if (after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { 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; goto insert; } =20 @@ -857,7 +849,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); @@ -920,12 +912,9 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) 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 */ 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; @@ -2209,33 +2198,24 @@ 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) { + *last =3D skb; + continue; } =20 count =3D min_t(size_t, len - copied, data_len); @@ -2254,14 +2234,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 { @@ -2417,22 +2395,17 @@ static bool mptcp_move_skbs(struct sock *sk) static unsigned int mptcp_inq_hint(const 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; + hint_val =3D READ_ONCE(msk->ack_seq) - READ_ONCE(msk->copied_seq); + if (hint_val >=3D INT_MAX) + return INT_MAX; =20 - return (unsigned int)hint_val; - } - - 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, @@ -2441,6 +2414,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 @@ -2459,6 +2433,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; @@ -2468,7 +2447,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) @@ -2478,8 +2457,11 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, =20 copied +=3D bytes_read; =20 - if (!list_empty(&msk->backlog_list) && mptcp_move_skbs(sk)) + if (!list_empty(&msk->backlog_list) && mptcp_move_skbs(sk)) { + if (flags & MSG_PEEK) + peek_seq =3D msk->copied_seq + copied; continue; + } =20 /* only the MPTCP socket status is relevant here. The exit * conditions mirror closely tcp_recvmsg() @@ -2522,6 +2504,10 @@ static int mptcp_recvmsg(struct sock *sk, struct msg= hdr *msg, size_t len, copied =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); @@ -3698,6 +3684,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) mptcp_pm_data_reset(msk); mptcp_ca_reset(sk); msk->bytes_consumed =3D 0; + msk->copied_seq =3D 0; msk->bytes_acked =3D 0; msk->bytes_received =3D 0; msk->bytes_sent =3D 0; @@ -3705,6 +3692,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) msk->rcvspace_init =3D 0; msk->fastclosing =3D 0; msk->rcvd_dummy_seq =3D false; + msk->tfo_skb_len =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -3955,8 +3943,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 @@ -4628,7 +4618,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; @@ -4670,11 +4660,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 c317d8b59fff..985ef15275eb 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -131,7 +131,6 @@ struct mptcp_skb_cb { u64 map_seq; u64 end_seq; - u32 offset; u8 has_rxtstamp; }; =20 @@ -311,6 +310,7 @@ struct mptcp_sock { u64 rcv_data_fin_seq; u64 bytes_retrans; u64 bytes_consumed; + u64 copied_seq; int snd_burst; int old_wspace; u64 recovery_snd_nxt; /* in recovery mode accept up to this seq; @@ -325,6 +325,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 recovery; /* closing subflow write queue reinjected */ @@ -884,6 +885,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 49a000b8dcb8..899ffaba0b2b 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -536,10 +536,12 @@ 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)) { + 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, @@ -556,6 +558,13 @@ static void mptcp_propagate_state(struct sock *sk, str= uct sock *ssk, WRITE_ONCE(msk->snd_una, subflow->idsn + 1); WRITE_ONCE(msk->wnd_end, subflow->idsn + 1 + tcp_sk(ssk)->snd_wnd); subflow_set_remote_key(msk, subflow, mp_opt); + } else { + /* Fallback (no MPTCP options at SYN-ACK) */ + subflow->map_seq =3D 0; + subflow->map_subflow_seq =3D tcp_sk(ssk)->copied_seq - + subflow->ssn_offset; + WRITE_ONCE(msk->ack_seq, 0); + msk->copied_seq =3D 0; } =20 if (!sock_owned_by_user(sk)) { @@ -1492,7 +1501,7 @@ static bool subflow_check_data_avail(struct sock *ssk) skb =3D skb_peek(&ssk->sk_receive_queue); subflow->map_valid =3D 1; subflow->map_data_len =3D skb->len; - subflow->map_subflow_seq =3D tcp_sk(ssk)->copied_seq - subflow->ssn_offse= t; + subflow->map_subflow_seq =3D TCP_SKB_CB(skb)->seq - subflow->ssn_offset; subflow->map_seq =3D __mptcp_expand_seq(subflow->map_seq, subflow->iasn + TCP_SKB_CB(skb)->seq - --=20 2.55.0 From nobody Thu Nov 5 07:28:00 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793349709; b=Um/guJ9WRlZrmXRaNj5H+sHpDosVMRKE16fOX8CJyopBm4izzU9uNlrq3yzn69W3sMlW WAUfbcokwaVIwxr7zMc8+nhRaKaejbTtIbPCiMbjCNd8XVnmn7pqIRqnAp+r1urgrTMpy Y9cdRxcDE9gCoCPqBAxbgNLxjl6pJ/RZDrNZ4ymnOyk39Fyw7/hywoT3S093oJtUnFp4x 51LNA563vzF1MGnAD8kKiGm5Fml2V0RJThMBhMWLN0fsqtOrZDJQdATw0R9+zacYp1xWa dt5ZuEsA3Uw0Rau5cFbglgntthypYP/dtzSbe0QvjnFTlgkByAgtnKOh90v6vSbxPoQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793349709; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=tGWVAFd1aVbWWd9XS6yBtcW2oVB7wYL0nVZwTBynSHA=; b=dPKYc15At1E5myNvAP/qq8DN7pyk++cXiMwd8Uzg99vORIuefL309IXI65cQ1nqlvKav x4hgb9ciO+I359kS++347qLht/oYrzMIDCwYRaGHPUpeQSH0JpE7Jy2x9xubiFUiVELZ8 Fpql3/794NjXBRUH67OUr93+NWMEGe6fFwc6bRCcDdJcgxpGJRddLApnol8BGN5BaD6LJ tX8B0HNWMGkXvLib9qqFWOSVeReYJDvlhnBxq1EtgeoiAFCYtdj0E5AtMGuvJHHot4MP6 4lyPJhXerIPPo5tx/QIim53xVSgy4S7vpaBrB5XzEluJLKjTP+/DdkkRxHXCx015Y8A== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b="JWq/h7YH"; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7824606A320 for ; Fri, 30 Oct 2026 08:41:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=JWq/h7YH Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B5251F00A18; Fri, 30 Oct 2026 08:41:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793349708; bh=tGWVAFd1aVbWWd9XS6yBtcW2oVB7wYL0nVZwTBynSHA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=JWq/h7YHQSJMDiehe2ZdlY95KE0FZquhvPN4HNcU0FiEPuy/MKPHn5Ie+9FQgGfif lB8mLl/4cpSf6iFFGlygkmlHwKpBdY82iTWlemEdsG9ukzbJX4wyZ8pu75amYeOcn+ ZXBxgsRNG+ESNQpvOhu7YvARe1cPkuMzaj3tdJeI2scnUdBWdbJDFA05cVvVfADLu6 fDUfAJ3OiHvyF2/draCV2Fz9ha6HcPGTgb1yT+yAN++kgYzsGARGb2REWl0etuXCC4 ssDhPp47SRxgeN2WbRPkuEUvW2xRgYwLMlEWgI33wYLjtsEvHXHVXKN59+pFYVY/ic TCrVQci/Fo06w== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v18 4/5] mptcp: sync mptcp skb cb layout with tcp one Date: Fri, 30 Oct 2026 16:41:25 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list 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. The 32-bit sequence numbers are safe because all SKBs in the receive queue and OFO queue have been validated against the receive window (max INT_MAX), so their sequence numbers are guaranteed to be within 2^31 of the current ack_seq or copied_seq. This ensures that 32-bit arithmetic (comparisons and subtractions) produces correct results even when 64-bit values cross the 2^32 boundary, as the relative distance remains small. Add build time check to ensure the latter invariant. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 6 ++- net/mptcp/protocol.c | 92 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 +++- 3 files changed, 65 insertions(+), 40 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 792147b5279f..7195da74d5c7 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -168,11 +168,13 @@ static bool __mptcp_try_coalesce(struct sock *sk, str= uct 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)->map_seq64 !=3D MPTCP_SKB_CB(to)->map_seq64 + + to->len || ((to->len + from->len) > (limit >> 3)) || !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; @@ -254,8 +256,8 @@ static void mptcp_prune_ofo_queue(struct sock *sk, struct sk_buff *skb =3D rb_to_skb(node); =20 /* Stop pruning if the incoming skb would land in OoO tail. */ - if (after64(MPTCP_SKB_CB(in_skb)->map_seq, - MPTCP_SKB_CB(skb)->map_seq)) + if (after(MPTCP_SKB_CB(in_skb)->map_seq, + MPTCP_SKB_CB(skb)->map_seq)) break; =20 pruned =3D true; @@ -301,16 +303,21 @@ 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, + 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)) { + /* Use the full sequence space to perform the admission checks, to + * protect vs possible wrap-arounds. + */ + if (after64(MPTCP_SKB_CB(skb)->map_seq64, max_seq) || + after64(end_seq, max_seq)) { /* out of window */ mptcp_drop(sk, skb); pr_debug("oow by %lld, rcv_wnd_sent %llu\n", @@ -345,7 +352,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; @@ -357,18 +364,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((u32)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 | @@ -399,7 +406,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); @@ -421,11 +428,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); @@ -448,13 +457,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 @@ -466,7 +476,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) if (unlikely(msk->rcvd_dummy_seq)) __mptcp_sync_rcv_sequence(sk); =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) { /* in sequence */ insert: if (!mptcp_try_rmem_schedule(sk, skb)) { @@ -484,14 +494,14 @@ 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; } =20 /* Partial packet */ - if (after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) { - copy_len =3D MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq; + if (after64(MPTCP_SKB_CB(skb)->map_seq64 + skb->len, msk->ack_seq)) { + copy_len =3D MPTCP_SKB_CB(skb)->end_seq - (u32)msk->ack_seq; goto insert; } =20 @@ -886,39 +896,37 @@ 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; - - pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", - MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, - delta); + pr_debug("uncoalesced seq=3D%x ack seq=3D%x delta=3D%d\n", + MPTCP_SKB_CB(skb)->map_seq, ack_seq, + ack_seq - MPTCP_SKB_CB(skb)->map_seq); __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; @@ -2207,7 +2215,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; @@ -4618,7 +4626,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; @@ -4868,11 +4876,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 985ef15275eb..9b073cbdf76e 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -129,9 +129,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.55.0 From nobody Thu Nov 5 07:28:00 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793349710; b=q4aD9BLhhlKbItnew5eo4TtGKfDXQU01Vn6smkBYKqub/nFG2ZW7HXK1yroG6sTuTrwh oMJTn3pd+g9DcBDS+9M50Ut84IKCuTjSsJkbHg/JiEHPjs76O4yMwOcRwLBv88x0Se91q W9zjHjYwzv80DOltFk6T7SU6i7DggBnZFvkf0zA1m+0+pYSUZ1UEITbj9sGlvk5k+9UZ1 bvozM4kAwC4H/W08UN6i5whXnD7XS24+1iCrO8Pn+sdnQ+5dP9Xmi70DvgLbOslnwkSW0 4G8m+BT+Qg3kJuw5ktH6tmFoetDUx+bZ4iBy1aZrDf7GYO+8+0+8o6VxZaUoNRnkGdg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793349710; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=wqWhvfGHwJiGDdh05d/ZPgn+VnaRmq6HfuNpvir3clU=; b=lklbC7+AQKpdCpS3XNv22Aoj4MKDvTZRGQWA0DgK5C+mUEXpBW/UOq4EasKr34QtgTXO B2ECm44wqvdHsmveetcSstBRs/INFyA0OLiQBjyVbu2nR2M2yG+plnoAOfd2VvrD5dk7A IZ8mvG1xHHTHE4UXL1A82EP+sMXAPjkUfsQ43st9BDppiD7LJOE4TyPNJmGTr6yI349/i YTn7lBZNXYMHwnXyvof3K2dLiKRjG2nHGBP9lFljcL42WAT5GY6mjkdTpoYuQS5u2SsYR b3yUtRXY4O+zCJ+rtR2n0h6fJ424RgDLsMXgKGzGsjCXxv3IOv6B+ikdI5aSC2O/4uQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=MSw6wANG; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3422F606A31A for ; Fri, 30 Oct 2026 08:41:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=MSw6wANG Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A8E11F000C1; Fri, 30 Oct 2026 08:41:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793349710; bh=wqWhvfGHwJiGDdh05d/ZPgn+VnaRmq6HfuNpvir3clU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MSw6wANG1x7Da1c7lMl/9fBTdXmFoYZgZkWv79+//nDsk0p646YuxLl/80WjUWWHE F4Wbi+nPfzpNyKjouwOFfe39MKVHsmi3/RWTK6G0ppr2Vb3Qaec0oBJjgMPp/SyGru p0ZgAOzncmiploEnmKstknfF3QC4gMKQ831LDMvTFbJqAbVblGeueMjj7yVSQIqA1R wrwOjvTdhor3Lkp6BHsmaJBP6UdkWKo2ltsCeslLOURZieIJwW3gP5189KxP2B1sc0 JzxJy8BL/yxniz305cAcsPOu2xqIIghmEmmUPWiQYOf54ePq8XbeDVaJFxHfhHFAbu EKSIpr3dcW9SQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v18 5/5] mptcp: defer read_sock cleanup to mptcp_worker Date: Fri, 30 Oct 2026 16:41:26 +0800 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni When MPTCP carries TLS, __mptcp_read_sock() is reached from BH context (via tls_strp_read_copyin() -> sk->sk_read_sock()), where calling mptcp_rcv_space_adjust() and mptcp_cleanup_rbuf() is not safe as both expect process context. Move both calls to mptcp_worker(): __mptcp_read_sock() accumulates the consumed bytes in msk->read_copied and signals the worker through a new MPTCP_WORK_READ_COMPLETE bit. The worker drains the accumulator under mptcp_data_lock() and runs rcvbuf autotuning and RBU update in process context. Also remove the backlog flush from mptcp_recv_skb() (covered by mptcp_release_cb()), drop the msk_owned_by_me() assertion (BH caller does not own the msk lock), and drop the redundant mptcp_recv_skb() call after the main loop. Initialize msk->read_copied in __mptcp_init_sock() and reset it in mptcp_disconnect(). Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 37 ++++++++++++++++++++++++++++--------- net/mptcp/protocol.h | 2 ++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7195da74d5c7..a59247495987 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3136,6 +3136,21 @@ static void mptcp_backlog_purge(struct sock *sk) sk_mem_reclaim(sk); } =20 +static void mptcp_read_complete(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + int read_copied; + + mptcp_data_lock(sk); + read_copied =3D msk->read_copied; + msk->read_copied =3D 0; + mptcp_data_unlock(sk); + + mptcp_rcv_space_adjust(msk, read_copied); + if (read_copied > 0) + mptcp_cleanup_rbuf(msk, read_copied); +} + static void mptcp_do_fastclose(struct sock *sk) { struct mptcp_subflow_context *subflow, *tmp; @@ -3211,6 +3226,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_READ_COMPLETE, &msk->flags)) + mptcp_read_complete(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); @@ -3254,6 +3272,7 @@ static void __mptcp_init_sock(struct sock *sk) msk->last_data_sent =3D tcp_jiffies32; msk->last_data_recv =3D tcp_jiffies32; msk->last_ack_recv =3D tcp_jiffies32; + msk->read_copied =3D 0; =20 mptcp_pm_data_init(msk); spin_lock_init(&msk->fallback_lock); @@ -3701,6 +3720,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) msk->fastclosing =3D 0; msk->rcvd_dummy_seq =3D false; msk->tfo_skb_len =3D 0; + msk->read_copied =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -4622,9 +4642,6 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk= , u32 *off) struct sk_buff *skb; u32 offset; =20 - if (!list_empty(&msk->backlog_list)) - mptcp_move_skbs(sk); - while ((skb =3D skb_peek(&sk->sk_receive_queue)) !=3D NULL) { offset =3D (u32)msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; if (offset < skb->len) { @@ -4639,6 +4656,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) @@ -4648,8 +4666,6 @@ static int __mptcp_read_sock(struct sock *sk, read_de= scriptor_t *desc, int copied =3D 0; u32 offset; =20 - msk_owned_by_me(msk); - if (sk->sk_state =3D=3D TCP_LISTEN) return -ENOTCONN; while ((skb =3D mptcp_recv_skb(sk, &offset)) !=3D NULL) { @@ -4680,11 +4696,14 @@ static int __mptcp_read_sock(struct sock *sk, read_= descriptor_t *desc, if (noack) goto out; =20 - mptcp_rcv_space_adjust(msk, copied); - + /* The backlog flushing is only needed when some data is actually + * moved and will take place in mptcp_release_cb() via + * release_sock() in the worker. + */ if (copied > 0) { - mptcp_recv_skb(sk, &offset); - mptcp_cleanup_rbuf(msk, copied); + msk->read_copied +=3D 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 9b073cbdf76e..7441da7704fe 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_ENABLED 4 +#define MPTCP_WORK_READ_COMPLETE 5 =20 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 @@ -326,6 +327,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; --=20 2.55.0