From nobody Thu Nov 5 07:28:14 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=1793327422; b=hstD3agX4GEiqD2P28SqzcD3uLQyt83PEgcCXK0FbBZUxVW7CTlTXasQ5ZPH9nbCFpFE Wj1tuDrHbfdkSOpLbdm6WzTidLW6D2GFNTb4u/6PSFbaG9mtqm3ZHgPIHPBM2RZt96YVk n96rgqL7T9JnSDYohn3ryYB0oUkOlKpfddmyihzK/pZLu0Sdy8sazCkbOemAIIT5y0Out yQfSgc2Id7gJxIhL3fRcFxwwfW1bT4vtnkl7nleUI/qhzKlyn6/hTZAJkWgGHCLk4olTl 6G1oIWYkTAGfqvCPmIRKfmm19GiDXQFHohmPIUnNx+nH7Pev2Tzpts/4R11UOwdLtdw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793327422; 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=CDuYKc5tE8fEuySmgJyEJpudK3B31G8771tsDRobI2YzmZ8nlre/Z8Sd+YWJCduw3KzL fVcERjiXJXA29tXGVjQ4bbtq8qtwLLNjidZ8ZBX+IxwYssnlftMUHLDsofx91hKAb0Nxz sgOZV3XnDEYYRSYB1imhGm6Po+aI4pRZB7DAdXk+7FBxZOtIZybqf1iIDomISNrobIzJq OGYOhJRMJBEHyHuayVph3kDmCLj+FNVVkFd4yNomXPo2ajNdAlGArSXlbxY9u/BuMky8m /6c4vrIKYwJ/wMTftORCqMmZmOVReY8Qine4TbBoFUWR/hz71FOGWXFhngH+i7ED6PQ== 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=T0hLR9f3; 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 17469606A31F for ; Fri, 30 Oct 2026 02:30:22 +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=T0hLR9f3 Received: by smtp.kernel.org (Postfix) with ESMTPSA id C0BA51F00A16; Fri, 30 Oct 2026 02:30:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793327421; bh=1J8C7pphSK2zVga48ZXLypGHUwLsv9JZ0n5GsGZOvyg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=T0hLR9f3/iY2nG2jXHHZfS80yX/FyY872gszqEhTApeg6x0UDRNecRm/G0Xp7ZTKL XykzBW4qtXdbs/us9/cUjZS2BZopSOc+bThENhWP0oXO/zpMTqGupJVDKgENMXc5sh xeXiKJt59wQtX4I5pPn7ek5p7Kjxul59bCIm8aewC2hTTI5+lyNuYgeb5OCvz+j/+n 3ykNB14uGCZdul56UCTqGIJsuQ7Z7lSYdMEQPUDubwKyohF1vTlGfYxSnpXNO2zjRW 09Z4G9BKELsR1P++i14ZW0oCwNrUUrtDMwtjq260SxBDPl8tVh0Cm14lLz6VZYly1S DTKsOvHDrfSAQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v17 1/4] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Fri, 30 Oct 2026 10:30:12 +0800 Message-ID: <2d215e3e2e2dd8d339239043810610a2618d31d6.1793326853.git.tanggeliang@kylinos.cn> 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:14 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=1793327424; b=lwQ4hVlxck3vO9vRexsYueCxU72gD+iBVjqoJUc3S6a472qrQZ49WNDnNZ38nqE3MuZ6 j+zycFNth1O2d6SltJoQPXUnHnDyKpddpudyosWj2Lkg4oKz8itW5wbIsary+YeIYd1Nv BYs9kOL6LO1JgFvJ4L5LWEcg0AJY04u2amVGOpCZ7mmCCBWohL9AI23E6S8hLDb1waxx7 L3MDCx3ezn2umoQdTilEuEUOo3RaTkr31/D2IoSFF9s5MzfHjoAvUWOQy4ZwcZW5OmA62 N3Py8yoAkuF2KNYu/vka6rmFq4lMh6tkyJeba6mtVyGM0U8yfA9KPoxjeu45f6LbBOQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793327424; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=/2aSQJ+FAJqI1UFGfQdZ7HR0EQ7cNqLpAGJwH7cxOug=; b=EzeuJ0OGFzg6Nj2svJ5yThySL9Bd8u0x2LGyZHfILPc6EtUv1K+DVv2cLZTb0QzU55sj Z38sCD7JA3ijCOxbIq4sQCrCWAI8d57HvdEh17L6i5XqrwGd1r3RmsWfkpkF1CxLmcAm5 HUw1F+WSMn5ku/jcJgYDu74RAyoCL1GUypjefIKvWiEjdCbns/gIFQcV5QIzf++Fv+uEg 3KYfx5KtX/MNrshsSr/XZBHRZ2uvFeqNOZjbA+e43eoXpnTk2wfrQ9Cmr1rTHkEOj33OQ pdUm/iByxOJZ155MGEjo9nbpGkpoquRRSGN9JKtvjD+hnY14QZt8dMjl7PdQ7AF2D7g== 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=MBNfggsx; 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 D3192606A321 for ; Fri, 30 Oct 2026 02:30:23 +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=MBNfggsx Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6525A1F0093A; Fri, 30 Oct 2026 02:30:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793327423; bh=/2aSQJ+FAJqI1UFGfQdZ7HR0EQ7cNqLpAGJwH7cxOug=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=MBNfggsxm/6fC07rXFNKaJWL7/8PIlwPpO2pxt4aeLUCVTEzMGFwh80ZpUtunqKLU VILPnY9otHbNPH2E346jFp/dUTEh0fyS6DAw3oax8xtHmgWOS/+E+1/aU3qNCNITAV Pj4QBu01ev4ZzMbL2gGNBlOSHqGRe70imXhO/cHo5cQV+uoA4EbtX9ocB5IX1/b0E6 egzLc2h184Z4VWe+tufI1mKH/xEhbFQZKJIfEqmaEPpdBxYzwVjO0XoZeb0pMkaIvQ 67AxtpMw6oxwfFRtaUVw+GDBGADrPIv1l/LYeJ8fZxEMd3TH6nmz4uBp7MEmy0YKP3 0SAypl2wE0n+Q== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v17 2/4] mptcp: remove CB offset field Date: Fri, 30 Oct 2026 10:30:13 +0800 Message-ID: <9a98772b14e535454de5bafbf113aa72a3ee6f44.1793326853.git.tanggeliang@kylinos.cn> 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 copied_seq field to track the bytes already consumed from the MPTCP receive queue, carrying the amount of bytes already copied to user-space, alike what TCP is already doing. The newly introduced copied_seq field (u64) is always accessed under the msk socket lock. For TFO synchronization, subflow_set_remote_key() checks if copied_seq still equals the initial TFO value (-(u64)skb->len) before updating it. If user-space has already partially read the TFO data, the progress is preserved. WRITE_ONCE/READ_ONCE ensure proper memory ordering between BH context (3rd ACK processing) and user-space readers. Since both map_seq and copied_seq are u64, the offset calculation (copied_seq - map_seq) is straightforward. We check copied_seq >=3D map_seq before the subtraction to prevent underflow, which is critical for MSG_PEEK operations that traverse multiple skbs without advancing copied_seq. 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 __mptcp_recvmsg_mskq(), __mptcp_move_skb(), and __mptcp_read_sock() by removing per-skb offset tracking and will also make possible the next patch. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 12 ++++++---- net/mptcp/protocol.c | 53 ++++++++++++++++++++++---------------------- net/mptcp/protocol.h | 2 +- net/mptcp/subflow.c | 22 +++++++++++++++++- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index f717750906ff..04b1038b5200 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,23 @@ 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; 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->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; 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..f3b1b6b282a2 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -169,7 +169,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, =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)) return false; @@ -416,8 +415,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; @@ -426,9 +424,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; MPTCP_SKB_CB(skb)->cant_coalesce =3D 0; =20 @@ -472,10 +470,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 @@ -833,7 +827,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,12 +890,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; @@ -2195,11 +2186,22 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, st= ruct msghdr *msg, int copied =3D 0; =20 skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { - u32 delta, offset =3D MPTCP_SKB_CB(skb)->offset; - u32 data_len =3D skb->len - offset; + u32 delta, offset =3D 0; + u32 data_len; u32 count; int err; =20 + if (msk->copied_seq >=3D MPTCP_SKB_CB(skb)->map_seq) + offset =3D msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; + + /* Skip skbs that are entirely before copied_seq */ + if (offset >=3D skb->len) { + *last =3D skb; + continue; + } + + data_len =3D skb->len - offset; + if (flags & MSG_PEEK) { /* skip already peeked skbs */ if (total_data_len + data_len <=3D copied_total) { @@ -2233,11 +2235,9 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, str= uct msghdr *msg, =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; + msk->copied_seq +=3D count; + if (count < data_len) break; - } =20 mptcp_eat_recv_skb(sk, skb); } else { @@ -2394,11 +2394,11 @@ static unsigned int mptcp_inq_hint(const struct soc= k *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); const struct sk_buff *skb; + u64 hint_val; =20 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; - + hint_val =3D READ_ONCE(msk->ack_seq) - READ_ONCE(msk->copied_seq); if (hint_val >=3D INT_MAX) return INT_MAX; =20 @@ -3674,6 +3674,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; @@ -4601,7 +4602,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; @@ -4643,11 +4644,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 3be60da12924..5c1fa117e5d5 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -130,7 +130,6 @@ struct mptcp_skb_cb { u64 map_seq; u64 end_seq; - u32 offset; u8 has_rxtstamp; u8 cant_coalesce; }; @@ -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; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 78e886b20258..6a66841ca24a 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -533,6 +533,26 @@ 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 (subflow->is_mptfo) { + struct sock *sk =3D (struct sock *)msk; + struct sk_buff *skb; + + skb =3D skb_peek(&sk->sk_receive_queue); + if (skb) { + u64 tfo_map_seq =3D subflow->iasn - skb->len; + + WRITE_ONCE(MPTCP_SKB_CB(skb)->map_seq, tfo_map_seq); + WRITE_ONCE(MPTCP_SKB_CB(skb)->end_seq, subflow->iasn); + + if (READ_ONCE(msk->copied_seq) !=3D -(u64)skb->len) + return; + + WRITE_ONCE(msk->copied_seq, tfo_map_seq); + return; + } + } + WRITE_ONCE(msk->copied_seq, subflow->iasn); } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, @@ -1485,7 +1505,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:14 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=1793327425; b=NTnc5nzd18cjW+FAY8+lgyjcS8pBP9DZoUcETiyzLeJKuwWdQI8jPYm38l3F6yr8u4iU 9xeURVcIRizlCoM44ZoG8xN3l0XCKbymDphk8yUAd1nIUJ3DbJvAPtN7sDcZ2gWRT5UZP ySfNWsrwBYGcvuuZXlE++7YNRjYDlqMEvB/AhZKVajNmTJPHduXLNFjkuAfkSNYrQIfg7 SQABh99eHyjRABgRib5A70LEx+8EafdRIoC6X/Y9Rr1ajp1z0kWz5fg6vi5hKuL5YSLSz rqjBchwt+86fd2X2R9yTAfhtWpuPAyGak22DPOnZUFOEkPIYcjUXIoxKJUTsxP6GrfQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793327425; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=U0CGyVCXYRcXN1ZfpDY+iJ+xrUaTb9VDYAnZdTunyFg=; b=D/+xnJ/gPT/OY4X9zH8Rcro8NoT7PAtmJFLBo9UqPAE6Pegt6bIhhBapdNLohCWtGRzq POgR601H/d0OPujvdC8ldux9H3PJCmDvk+8XABiQEJ1Jz7AhZ+NimjH3FBGIkEnjZmKLN 7YUBlnasesuHA/Gp7X5TQKYsSJrKlD3HseRcqioShAygcbmZD1NF6eKsniXmIkOgOYueU EKTPNrD3ORHbKgb61UMDAO5A9MbmeXc+m4a71XLcu6XZavEPaVNaWC0/Uytx5dRZqOF2t KF55tbz/FTDz8bFcvKxY8K9TtrodRlRwxNCdGgElqn/5uvdFqi2S8crpK00np7ai4Kg== 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=T1FkQH7L; 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 7373D606A321 for ; Fri, 30 Oct 2026 02:30:25 +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=T1FkQH7L Received: by smtp.kernel.org (Postfix) with ESMTPSA id 121431F000C1; Fri, 30 Oct 2026 02:30:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793327424; bh=U0CGyVCXYRcXN1ZfpDY+iJ+xrUaTb9VDYAnZdTunyFg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=T1FkQH7LCVJrlA6tQBiG2w7vb5lt+wwCQdPRe6GW91PimAWQ/62Wcd2P3n1+8o0lr h4fTbJuwlV++saIoPgKFQAhv8SvB7A+Lz9qdyv8zfoMCi8JU1SHM0FY5c5uBeN8TJG TdNupuRkhM0Q9QPuCuWTzu26RQY7/nugqXYRuS/F1b+mRXj/9tL8vCo3jTe8at/Ozt fuUqIDfMAhJF+qtvJnA7aUfqtFYtzw02EPfbPQZeuqL/L/wOKXa4tWl3V3t3kzR90B YG7RA15sjVi1xWEbhkROlzmogygqh3GFz/p7SBFZU0orGBSm55GnTFLprf7eAupjWg yHwhcW+2OYl1A== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v17 3/4] mptcp: sync mptcp skb cb layout with tcp one Date: Fri, 30 Oct 2026 10:30:14 +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 | 90 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 +++- net/mptcp/subflow.c | 3 +- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 04b1038b5200..08f0402324c2 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; MPTCP_SKB_CB(skb)->cant_coalesce =3D 1; =20 @@ -57,7 +59,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); =20 msk =3D mptcp_sk(sk); - msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq64; 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 f3b1b6b282a2..8447efa9dee6 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -168,12 +168,14 @@ 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 || unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || ((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; @@ -255,8 +257,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; @@ -302,16 +304,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", @@ -346,7 +353,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; @@ -358,18 +365,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 | @@ -400,7 +407,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); @@ -422,11 +429,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; MPTCP_SKB_CB(skb)->cant_coalesce =3D 0; =20 @@ -438,13 +447,13 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset) =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 mptcp_borrow_fwdmem(sk, skb); =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)) { @@ -462,14 +471,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 @@ -864,39 +873,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; @@ -2192,7 +2199,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, stru= ct msghdr *msg, int err; =20 if (msk->copied_seq >=3D MPTCP_SKB_CB(skb)->map_seq) - offset =3D msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; + offset =3D (u32)msk->copied_seq - MPTCP_SKB_CB(skb)->map_seq; =20 /* Skip skbs that are entirely before copied_seq */ if (offset >=3D skb->len) { @@ -4602,7 +4609,8 @@ 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; @@ -4852,11 +4860,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 5c1fa117e5d5..2ab8342e198d 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -128,10 +128,13 @@ #define MPTCP_SYNC_SNDBUF 7 =20 struct mptcp_skb_cb { - u64 map_seq; - u64 end_seq; + u32 map_seq; + u32 end_seq; + u32 unused; + u16 flags; u8 has_rxtstamp; u8 cant_coalesce; + u64 map_seq64; }; =20 #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 6a66841ca24a..5a8d837e55d0 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -542,7 +542,8 @@ static void subflow_set_remote_key(struct mptcp_sock *m= sk, if (skb) { u64 tfo_map_seq =3D subflow->iasn - skb->len; =20 - WRITE_ONCE(MPTCP_SKB_CB(skb)->map_seq, tfo_map_seq); + WRITE_ONCE(MPTCP_SKB_CB(skb)->map_seq, (u32)tfo_map_seq); + WRITE_ONCE(MPTCP_SKB_CB(skb)->map_seq64, tfo_map_seq); WRITE_ONCE(MPTCP_SKB_CB(skb)->end_seq, subflow->iasn); =20 if (READ_ONCE(msk->copied_seq) !=3D -(u64)skb->len) --=20 2.55.0 From nobody Thu Nov 5 07:28:14 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=1793327427; b=Mab1HZpfgt3SQNR+NtwqNg7ke+3QsDo4S+Q5/il/wtyPMRP6xHhUWMCaRyece+4hkMiS 6ozTWcYXEfuC6MlGSerSik2HJqsuc+fH9tKEKhyeXw6tf8MWVArjnBrK5ybkRk7oWe/7T um4T/2YBU7xTdHBOCjE2ITGDkfVbx1tleVkjwYLx/1+atzCU2hCPszJhptjF5YHMUQpYx Y52fYB99FAui9h5MvWKXvdbwOpx5X1+l9B4cYcTAPLLGjxbYfEwb6+c1pTXhJNczawUPw tujyhvn5Ilx41PENeCpl7SPzFt22CGK+VZQbyXxF/QdHdpP0EtuLU5LPbKZbFS3syEg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793327427; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=75UkmwvrSrx8JixH9eK2sB+gRor+D0VBJwMxmd5StDw=; b=GBapwkGMb6gYYiBKFC/yQxZG01l4Y/iPCsQfG8p7k37TN9fL5FophI0m0TYY023EeJ0S 6dfqUJRfBmBTebZ4TWom+LAL6G3YBKMRr07RuVnnMq1rAA6oEiyaxc7ionskx2J/5xcIW 00C+7/Rlu8I2fpikVO85/0mkHyvXaXzoay9mMnxr4J+wgwHE6Q5LouPCR42wFH28c6oe/ z1RKXj6PlPVjuGSJmyMjju0ZCSr5wCQ07jCQ9SIxSxDk0N5zp41l4qfJq5W+LduRUYe2F Uwpp4ilQbrLg+rEQcPywWEad6eiaAJK2s8JhCtV/puLtenZh4Xa6lDpC9qUEOeNrMFg== 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=gdnbhAXb; 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 AF410606A31C for ; Fri, 30 Oct 2026 02:30:26 +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=gdnbhAXb Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7D9FE1F0093A; Fri, 30 Oct 2026 02:30:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793327426; bh=75UkmwvrSrx8JixH9eK2sB+gRor+D0VBJwMxmd5StDw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=gdnbhAXbMQUqnw9E5DJaLOPCxNOXYhru9f6VjdE5Tb8WL2iQdjTHRCr6ezOL9zIMI EJYNm91xU0oiMtaKrv1FWs6mKNobzPixmWxV098akbwoPkG62tjA5N4/gSz/ma+4wa t2njCfVHYfstxkfLbCBnN6Q6JwNAU3hBxVYtQt90+xXMOjX/B/1oy46Ch26eWyKeaz js1gGWXcgKJfZN9Db00D7m8jqbMRaR3G81Xla2XoSni2IRA/Rpa0sEBKPE3okzJkp8 nTHtPv5pCZInUtFqTLCVuD/7YHta8ARzYVeKcLo/z4CEKCGQcDF1bQTJVg3ZHJdMwW Si3Yal5GI39Kw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v17 4/4] mptcp: defer read_sock cleanup to mptcp_worker Date: Fri, 30 Oct 2026 10:30:15 +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 8447efa9dee6..8139f457cbb0 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3125,6 +3125,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; @@ -3200,6 +3215,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); @@ -3243,6 +3261,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); @@ -3688,6 +3707,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->read_copied =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -4605,9 +4625,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; =20 @@ -4623,6 +4640,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) @@ -4632,8 +4650,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) { @@ -4664,11 +4680,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 2ab8342e198d..b0082e1c83f0 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; unsigned long flags; --=20 2.55.0