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=1793696251; b=LyiVFJpN5G/iK+cy+HXvGcsmHdhM1kbDQYLHGM56kEWWy2ObBgJp1oam82682FAAUH1t yuvKRBjd8ERL3HtVAj10+wSH2G0qLDFgYqZSG3QZn6wAwC404Y/WxjOy5vWhLMdFBHMAo DGjRnUlqZfXKXYoK5T2wJSePskuT1QYKu+FVjdh+aI4jHlua5S92l2D7XFgYU/3G7RMv/ y6419YW8n5dEfgY3W3GHyeR2e1/XAzi1hPOLlwlwhHQiVfAwyCNHJDmAbuW50ZV8mQvKR /pg94p1xIipGK3DUIQQa1qrcYKWuJGQF5hLtKF0+XwknrChLJsTH4q8hLrr9y2GbcrA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696251; 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=aRUiCvCkBCo5feZPIWLYFUXyxAv0HVR+nzyye1pKrAlHX/JKQ5ElsrKuqdn8FHz+Fsac M3Y7QPDmpgsfmfxurzX0D85xHeRmBC91qwCNjox+IpQLPxt3eFFpIJPr59eLnjP4BP3H0 2aljnQ3Mpo6yPwzeOfR9dfAIM/OQMceeDz1V3Tco3/qF9qDpyOBVZonA17sPbTMZ2hkNd AGAuX/A3OHai18pM4GGNmqgXo1Ikirgtl8xQH64ib7bRKFX5uBxKoiSXlQ37juK1JbxxM BKNM43WTQPAFOBEVQEqXrM3//BZ7ongvGYHjH9ayeIlNm64CI83iigVjFmlOOBLRVhQ== 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=VKw4MMPb; 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 A1075606A326 for ; Tue, 3 Nov 2026 08:57:31 +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=VKw4MMPb Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2CA681F0093A; Tue, 3 Nov 2026 08:57:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696251; bh=1J8C7pphSK2zVga48ZXLypGHUwLsv9JZ0n5GsGZOvyg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=VKw4MMPb7aH6G4/gTnQ9tNfbltvxiUHbjiHZwrS6M7fJJz3rQrUkshw3MNbvBFFwH H7dDM8ytJ3D1OKnWFi8BJT4xtUwgcjnA2oxK17w3QilbIRFA6ng7SnGHLIQV7ZNffG OvkFAz+VQLtpNamfc+frfpAKT56sAYOGBjtRGJPpAkJfWl+Gw8ldTi1lka38Z1COEi j6L9z24cC2UOqHQ2yfwxSe643lk7SVKbxtWiGC04PJ5UZ787eVtpF6Sk7qD8cccvYC r4i+X3EALHHylgChleLiZEUzFhqgpJ5eLkEaCxZKDMMgeFYr4oyobAHx8SS+YOMyAS hqzm4pdOjoFIA== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v20 1/6] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Tue, 3 Nov 2026 16:57:20 +0800 Message-ID: <828c767192751734fc92ee2587957b49e7845a8b.1793695518.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=1793696253; b=GesZ5VN/J5t7kZixKUhIZ0yzfwnEgDD1E96yjF7OwJa+9WLMbT0bRrbSTAKC6vVnbC1r 69UD4N+BF6bX5qPIsNSNrappIhiGlFy5P/udFf+fpB6JSYEh6a3Jo9gjlKL6R0TUhNXrX cjWobVuE3iSB8eXOzgRcUzXGuJ+pOkwj5xnJXZ4YfHBSSGnFHC/m1npUyQjfmvzuaNj8b fKw2DzOa7iTDKA2T0QdXm4Ezd4zdDOgbUPrlWwx4Yuf47AbUYaiCiSX3akzDxQ9EGL4/e TmxdQ4EKCMtoRuwI1gYfESvk1HiXsZaRpRFSKMRdI36Ek8pQgT4JhaNwLr7SvGJuM3Q== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696253; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=OFlxCgDnDvmEQi2cuYoz06WpcnaSDHZS7jYFTK4iCIM=; b=2allICQMNLySm0s/sX2gd3P21XIcDjP0M62fzwZxpA/MZ/A4ay14vVTVTKOwqjkyqk6H lJbK74aACmMVPKVUEwzG/wZlrMRMB8goWt95fRI0OKjTW0meKOjAN8X0HxBZ1aG8rilhX GNjUGuiQMTjnnAM5r5in/PVQ20Y34GMqie5ypu9Xw82NfZeUuvHXk/rF9kpY9J6BnPd7Z at4yoaci/4xM/W2YtbY4VE3ECa6J+dFiLI4iYcVfHpf/wf/B36zgdenMtr49OohaFaRzr u21o7GhXxQX+VsuIBN/TtGPfo+uD9HUfKAkmajw1Ag1sWlbBcUo5lXPRzKULD7TKEkA== 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=Y4yKFi4e; 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 5C319606A32E for ; Tue, 3 Nov 2026 08:57:33 +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=Y4yKFi4e Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C1DE1F000C1; Tue, 3 Nov 2026 08:57:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696252; bh=OFlxCgDnDvmEQi2cuYoz06WpcnaSDHZS7jYFTK4iCIM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Y4yKFi4eOnlwRL0sWr/9cqn+9SjTtKhPOS5hey+CecKSviq5ZP5SXrqRrLuaXtdK1 7WVoo4ODV2i9WeO0YQK5OPj8tt8g3cMbFCd0kz8BvOXr9iUxkp/jGkqP1x7dRzggHk 7gwq3RmvZg39IYNa2CnL3SKQOnGnyNJTeMDDDb8OOAFQECDSXsP0B+MICniGB/GFn5 cpkI1qtzSthKO1G27/pGjHCGFh2nB4e240C3KIX6I2nrGx3Mx2nyPWzhJmblQAaxl/ 5GhveAmwexpqlnFpwhrck9bwheeJXDYPkueNDt/8P2OCFw59vOdq40GdqwKjss94M/ PuxSjeHeQ9x/g== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni Subject: [PATCH mptcp-next v20 2/6] mptcp: drop the cant_coalesce CB field Date: Tue, 3 Nov 2026 16:57:21 +0800 Message-ID: <9bd00acf2721c30b79fd852167b5b1343a2d67a0.1793695518.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 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 __mptcp_sync_rcv_sequence() to update the TFO skb map_seq and end_seq using the IASN stored in msk->tfo_iasn, and call it from __mptcp_move_skb() before any new skb lands into the msk. When the 3rd ack arrives while the msk is owned by user space, defer the sync via MPTCP_SYNC_SEQ in cb_flags. subflow_set_remote_key() stores tfo_iasn and either calls __mptcp_sync_rcv_sequence() directly (when the socket is not locked) or sets MPTCP_SYNC_SEQ for deferred processing. mptcp_move_skbs() and mptcp_release_cb() check MPTCP_SYNC_SEQ at each iteration before spooling the backlog, using test_and_clear_bit() since __mptcp_sync_rcv_sequence() can also be called without the socket lock held. A rcvd_dummy_seq flag tracks whether the TFO skb still carries the dummy mapping and needs synchronization. --- net/mptcp/fastopen.c | 6 ++++-- net/mptcp/protocol.c | 33 +++++++++++++++++++++++++++++++-- net/mptcp/protocol.h | 5 ++++- net/mptcp/subflow.c | 8 ++++++++ 4 files changed, 47 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..f3b07b303f55 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,24 @@ 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; + + if (likely(!msk->rcvd_dummy_seq)) + return; + + /* User space can have already received the TFO skb. */ + msk->rcvd_dummy_seq =3D false; + skb =3D skb_peek_tail(&sk->sk_receive_queue); + if (!skb) + return; + + MPTCP_SKB_CB(skb)->map_seq =3D msk->tfo_iasn - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D msk->tfo_iasn; +} + 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 +462,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: @@ -2375,6 +2397,8 @@ static bool mptcp_move_skbs(struct sock *sk) u32 moved =3D 0; =20 mptcp_data_lock(sk); + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + __mptcp_sync_rcv_sequence(sk); while (mptcp_can_spool_backlog(sk, &skbs)) { mptcp_data_unlock(sk); enqueued |=3D __mptcp_move_skbs(sk, &skbs, &moved); @@ -3680,6 +3704,8 @@ 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->tfo_iasn =3D 0; + msk->rcvd_dummy_seq =3D false; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -3882,6 +3908,9 @@ static void mptcp_release_cb(struct sock *sk) struct list_head join_list, skbs; bool spool_bl; =20 + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + __mptcp_sync_rcv_sequence(sk); + spool_bl =3D mptcp_can_spool_backlog(sk, &skbs); if (!flags && !spool_bl) break; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3be60da12924..b4e49d719200 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])) @@ -325,6 +325,7 @@ struct mptcp_sock { u32 last_ack_recv; unsigned long timer_ival; u32 token; + u64 tfo_iasn; unsigned long flags; unsigned long cb_flags; bool recovery; /* closing subflow write queue reinjected */ @@ -336,6 +337,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 +1195,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..8a3ba490b577 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,12 @@ 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); + msk->tfo_iasn =3D 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: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=1793696254; b=1mlKl7/3r1oYOkrEFJlB9ad03JAQoNaBKwklDUq3/y5XfMd6B6U8lQjD6DuHJW2SRzfj KRlc4+R7oabLgY/KDg1mHf9O4IUCqIn7nFtRkU1+ll9seVSxF9cb5Cbk/GEMNg4nsHLfI FmKf+2sLbrydSd3BWJQtWAv2XzDwx/5TtV/WqxPwHqpZPSzLMef+cUsMetonrv3Ggka/Z CKrH3tmZ6mKAf2JcUcZeO49JJilgsDxyhFf8xsbDfqJZiKLHcA5hN8GiD1cIN8h+WWmj6 9vhMnR9YS1tM7t4MjYueT3MfYXSLq7qCOwNcM7voPq7EfLby7ZknPqX+vi73lRIZZVw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696254; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=yJntaRQbzGVnzWYMHY7FegV5Yjg1bccMilBjtwueFxg=; b=rML2mYQv7wPPdkyWW/sjLxI3/xl/VY+bCLX5SHVGaucKQnvfRJyS2exKxCczHWL+C1i8 gM64+9SwRpe3AIc/uAIoatXFNgKLB3//uVpDWzB8KlqyfDNVoI0j+zeE2WWPHjlWi7N88 bQSmJy5USaYv8TjD2lFrExZlSXyLOuffBQ+rJ5PQktnICzLbJpR1s1E3qVDlkWFFRc8OA rSgZl0g2sbU6PQk1uHmBQKb1hE8Q/04iDYqlSgPPAANADcAS2iAUCmj8I9aSdjcVsC90p uL8fPWEXtjJXaRlvqq1sYKKc+Y/ebqkCusYBldWoVgAPFfS2rVzaArUaZybFJq0nNPQ== 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=AWFQRtF5; 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 8B21C606A32D for ; Tue, 3 Nov 2026 08:57:34 +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=AWFQRtF5 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6F7EE1F00A16; Tue, 3 Nov 2026 08:57:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696254; bh=yJntaRQbzGVnzWYMHY7FegV5Yjg1bccMilBjtwueFxg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=AWFQRtF5GzgaBZOuuBk2meYJHTJi17Pp2w2zngbbF0rOQ+wsgQUM7qdXXUznm+Zha ugNnwT2CCJrGqaVAQ+VI65OyHaKBmCJrOIFkADpZyVzeuNwkJCd03lwHh0L5ZyTZ75 0koJEOTsEo/4CDrGf9QNApED3J6Y2ahxg3zDqzwhMfOkZZBkdvk2l7o/uhg5bJ9a1Z pW34BTkTPVqXl2FqW4vmjr6YiRrVu1R8/8j9CVHw6GMrIJb1MSpcObUq2x0EOn/bGC GZQycXrMACwmdI+9T30w7XMxm/VMb6fKY1Vgit7QM/emNSRAV2t8KbGjc0bpxZo74Y 6Eick7EGhoMQw== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang Subject: [PATCH mptcp-next v20 3/6] mptcp: fix TFO map_seq sign extension in fastopen Date: Tue, 3 Nov 2026 16:57:22 +0800 Message-ID: <6cded4388add37e9314abc3199507bec457000f6.1793695518.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: Geliang Tang In mptcp_fastopen_subflow_synack_set_params(), the TFO skb's map_seq is set to -skb->len to represent data before the IASN. Since skb->len is u32, the negation -skb->len is computed in u32 arithmetic, producing a large positive value (e.g., -1420 becomes 4294965876). When assigned to map_seq (u64), this value is zero-extended rather than sign-extended. This causes incorrect behavior in sequence number comparisons throughout the code. Functions like after64() and before64() may misorder TFO skbs, and the out-of-order queue handling may misclassify TFO data. Fix by casting to u64 before negation: -(u64)skb->len. This ensures proper 64-bit two's complement representation and correct semantics for all sequence number operations. Signed-off-by: Geliang Tang --- net/mptcp/fastopen.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index e18b31028e7e..79765cf55286 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -45,8 +45,10 @@ void mptcp_fastopen_subflow_synack_set_params(struct mpt= cp_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 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=1793696256; b=5BfvXFbf1hi4BLi2+2tvjwUa4OAYknur7fuSEwSjDd2ndoGvERXBjXpN32mkTqBJGLuh odTzo3fPaXQR9j/9E6MKaht/HQ9bcDH0vld8APPmaiOXPVl1tI779vpwVLGh0gCnY27VB X5CeY4MrOZwC1G9ytiJF1TedHiGjudPxg5iieTJcHYSOC+QAusrvONuquMhK7hYY6ilRq uWYto2eLkVjjKONw+KQ6R3qG67UmxjcFtCRu+lbnYam2kOUYrvBCOTxKZkUT8M9MuSZ9Z 2K1Rh1Y8fd4CJ2lwdWN2ZjMEU4Xz/aWO9UlIAQpgTvb9SvLbHCaUQKjsWsTHeEPoGVQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696256; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=4KiZ3dmr8gD7SWhOHGIv++CBSW7FDjFfn5WrCserku4=; b=nbcGTXJvp/yjdLKBORTC2NcBm5lietsCP697jFDxhStYHUQLpTEnS2MMmvSsw9ziKS2U MJnhHhtGa9NiH82E+dT2+Fc9RGglbrkGBCzNXj3JpIQd8c/BKV16ubvTiUnViKNWGztri 4qJILFsUCvY9foiUxHDuU10mF2rPSpEPPKF0E/XDR0znUNW/9D5CiPZBguzeOZcAno1BZ hGtmKeWL9VXhoPzXOjdn04o98zwJmuCDddYz0OZ0iFpScZ8CpSD5K+/4rIzDr9k2R8hgO F7zzDEh+ibyQrFmjb1FY2KBiJxMo3dKBMDFByZMFL1UcG1JmDGS2nPgjZXZ7SfIwuaw== 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=aHEhEXui; 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 5041D606D801 for ; Tue, 3 Nov 2026 08:57:36 +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=aHEhEXui Received: by smtp.kernel.org (Postfix) with ESMTPSA id CEC271F00A15; Tue, 3 Nov 2026 08:57:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696255; bh=4KiZ3dmr8gD7SWhOHGIv++CBSW7FDjFfn5WrCserku4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=aHEhEXuiZa32Pyc2fxzjzwEGYl6qXW2INA7Kk5A+oPIAYeYudpE85eQvIM89ipiO5 pVuWGbHEgmEFKZzCAU8KOae6dictif+zyYZxAnSO1qiX9MMx6e1Bqk1+VJUP9iAWi1 qxrODQpndmuDSDIgtOf0d5bgUcd9PdVVj9mY7uK/nf7ag47r/R+nKecyKhpzDkwHsF Mf3bNdaXJgptiDZg2GBcsJIrase/FAN58ElCSmY1mWbYFu+oyNPcoWsWRmGbL03ojB Owf+Mdv8oQJoqytR7DFYDbZ6eQJhkG3WBww24l9jVicVevhsg6uXF5kX78rLFlNDRn vzMm++EXgWb9Q== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v20 4/6] mptcp: remove CB offset field Date: Tue, 3 Nov 2026 16:57:23 +0800 Message-ID: <866f86ad2ea894fc21af7546ed0cf6f8b9d816de.1793695518.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 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 mptcp_move_skbs() and 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. 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. In mptcp_init_skb(), map_seq is computed as mptcp_subflow_get_mapped_dsn() minus offset. This is correct even when offset > 0 and the mapping is out-of-order, because mptcp_subflow_get_mapped_dsn() returns the DSN for the byte at tp->copied_seq (position 'offset' in the skb), and the consumed prefix bytes are part of the same logical DSN range. 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(). Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 2 +- net/mptcp/protocol.c | 93 +++++++++++++++++++++++--------------------- net/mptcp/protocol.h | 2 +- net/mptcp/subflow.c | 15 +++++-- 4 files changed, 62 insertions(+), 50 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 79765cf55286..78481c100e2a 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -50,7 +50,6 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf */ 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); @@ -58,6 +57,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; 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 f3b07b303f55..3bd7d38ce78c 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; @@ -424,10 +422,13 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset, /* the skb map_seq accounts for the skb offset: * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq * value + * + * This is correct even when offset > 0 and mapping is out-of-order, + * because consumed prefix bytes are part of the same logical DSN range. */ - 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); @@ -451,7 +452,7 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) return; =20 MPTCP_SKB_CB(skb)->map_seq =3D msk->tfo_iasn - skb->len; - MPTCP_SKB_CB(skb)->end_seq =3D msk->tfo_iasn; + 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) @@ -494,10 +495,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 @@ -855,7 +852,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); @@ -918,12 +915,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; @@ -2207,33 +2201,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); @@ -2252,14 +2237,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 { @@ -2397,9 +2380,15 @@ static bool mptcp_move_skbs(struct sock *sk) u32 moved =3D 0; =20 mptcp_data_lock(sk); - if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) - __mptcp_sync_rcv_sequence(sk); - while (mptcp_can_spool_backlog(sk, &skbs)) { + while (1) { + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + msk->copied_seq +=3D msk->tfo_iasn; + __mptcp_sync_rcv_sequence(sk); + } + + if (!mptcp_can_spool_backlog(sk, &skbs)) + break; + mptcp_data_unlock(sk); enqueued |=3D __mptcp_move_skbs(sk, &skbs, &moved); =20 @@ -2441,6 +2430,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 +2449,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 +2463,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 +2473,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 +2520,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 +3700,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; @@ -3908,8 +3911,10 @@ static void mptcp_release_cb(struct sock *sk) struct list_head join_list, skbs; bool spool_bl; =20 - 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 msk->tfo_iasn; __mptcp_sync_rcv_sequence(sk); + } =20 spool_bl =3D mptcp_can_spool_backlog(sk, &skbs); if (!flags && !spool_bl) @@ -4630,7 +4635,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; @@ -4672,11 +4677,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 b4e49d719200..7878e6ac6c0b 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; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 8a3ba490b577..71c3b148cf04 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -537,10 +537,12 @@ static void subflow_set_remote_key(struct mptcp_sock = *msk, atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); msk->tfo_iasn =3D 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, @@ -557,6 +559,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)) { @@ -1493,7 +1502,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=1793696257; b=bl3MMJ/QjgwtEVPTJKfIPawPuWt6U5dPtakbfGtb+M7pKpvUeDV4DA9DZ1QSfP7t0pPR GJYqv0ZQoI2t5EBIpFlMYJMipnRk0KQTxVmozsz2NWAjQ+Dq9BaAGxu+eDllp26TpdFv+ 7tGzq4tC2qwQmmVv4LDPosM95BBzyU5DihRzF9CUQjrMdY8WMlCPb8mxcmWCZpSAjzilk FmVVSFVsAS7zTKaGhOytvflq5TakCYQ6wqZJHy0J+yK8/W2T1AMUm39DlvX3ktSmHYKwL tILmct/nOzSVJaqxf8hx5sa6ouVgmwWrkpoP9yfREO7YjR5pyd35n88VtIM7uBmbsIw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696257; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=8llgsJBvrSemn2be+Mp6yjQui1PRyoRGMXd26JcbR4s=; b=sFpzWRIw9PLNYHYwK1V9pU/4I8uM4jb5EzYEAbZXaCo/J7HzJ9u3SyN+cuIeilgS05kp 0Xs0N627q4QU1cDjfFviIJ2C+JBZIhuOfq5gjFHe3ZEqrFw7nUSaPqUNPMQWknfmj9+wW bSQ5mnhEGUSjiD2Yy2tp6CeDz8Ic5WnkIwomIaQK+9NyWpxTQsMWhHA18Se+RvrEC/nLC U1g9YcusoADt/XH1d7tnZ1kAN6RNaO1+dQZAiWezhUx6qL0k93HD12U2IFOMaCerjt2k9 LdIyeDR/kHnCyeG8rmuHhgsL7csF/IeaOUdo0V9UZkxBgwGUcsyq67VBn5ytKizxhtw== 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=ZDNyK03O; 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 867B8606D80D for ; Tue, 3 Nov 2026 08:57:37 +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=ZDNyK03O Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5792A1F00A1A; Tue, 3 Nov 2026 08:57:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696257; bh=8llgsJBvrSemn2be+Mp6yjQui1PRyoRGMXd26JcbR4s=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZDNyK03OXEAnxWbSYngVFEWULUvexXDw54lQvZGXtOUKnBPyTcoIkIbVmg6XWWNkF MxsnOORyAs6vjAEXg9/I/1f2Fr0O7ZILK3bUetC2/0GklMWxwO3kfoIfZCdUnqJsn0 yAsVh8J4VqBvtyxV1eboyS086yc/QPcVmZPWGLxguxBben+q71m9Zq/PRqvfvsppsl F1JLXG7CDqWJtgmTbuKmXfPTZCglCC6AuvhHwSXPcGFeAstNYgl4/KI/mmUWSmDdUr UuqydeI7P9LoU32JEzAcCUXXYMk5WiUMrmD8ZA3evOcdUgT0RSj87fDNJJctR2Weh6 tQntSVKOWN9eQ== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Paolo Abeni , Geliang Tang Subject: [PATCH mptcp-next v20 5/6] mptcp: sync mptcp skb cb layout with tcp one Date: Tue, 3 Nov 2026 16:57:24 +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 | 94 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 +++- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 78481c100e2a..bd52e9528b29 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; 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 3bd7d38ce78c..3e10b06b7772 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,23 @@ 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); + if (after64(READ_ONCE(msk->ack_seq), max_seq)) + max_seq =3D READ_ONCE(msk->ack_seq); =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 +354,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 +366,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 +408,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); @@ -425,10 +434,14 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset) * * This is correct even when offset > 0 and mapping is out-of-order, * because consumed prefix bytes are part of the same logical DSN range. + * + * 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); @@ -451,13 +464,14 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D msk->tfo_iasn - skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D msk->tfo_iasn - 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 @@ -469,7 +483,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)) { @@ -487,14 +501,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 @@ -889,39 +903,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; @@ -2210,7 +2222,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; @@ -4635,7 +4647,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; @@ -4885,11 +4897,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 7878e6ac6c0b..fa54f70ab501 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: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=1793696259; b=U/goqkUIW0GwQMOTv4QA7IiKbZSQx19QjORyE7W8CxF3alYZIMFZlu+Y0kXafmB2ryOQ uuCGGm54b+gzDXZvrMwdbEZCce0A/ooUgaLe4EuEO6Eqvdjv/OtrqkuUA0PwJAhAfSzXU UxYdhen0pqmMD+hlQOHBHTaaP6LXy7FB/uJGCeATQY/BtSFZ+eVpZs5osL07E/s/AEBgS R70GO1CmAaxGl3oAovsYXgqGLBwr2lkEaMajhvkUPM629/xGN3O0i58B5yCwYbq/tTH6T oP3EVbKWlTosqF1QqaoPm+SIh+fpe7YXiF8+N7MKNSgxJq+O5S8U4VozLR+sUNO0Hew== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793696259; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=oMhmyIHQITW8+f0NpI/j7JCrVNR2HsEBSFaVwzb1ERI=; b=O4nldXy3+VPfKmuJlrvjH17+vHqwobICRM2IsHaCwULnJtlGkBEqNmNhy0PYPsRCLrXB GzTA/I8W9yzCtVzYf+e7qUB7q/H0fV5rid5Hmt46hfLBEBIm/KlNjAnhOZCT/eQ4X9+Ib ehz4t8qRvCF1S3WajtAhSNHgDVs9gMfa8SK1hbfYAF28S77GhyxHBrJ5VZ7odadcJ3aST JGN7FM9TBAnujxZOiA86Qn3w5RnjWIPAQCgVn3HQf2rJDoP71Q3dEJeJx2MP4o+HZCjO+ trDxrE5kVizWgqGz+p2uNAow6+lRjpr3o0/SRQdejEVGpO3OLWUHJG3mRsp8Z2+RjAg== 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=W05LwyrA; 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 23D1D606A32D for ; Tue, 3 Nov 2026 08:57:39 +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=W05LwyrA Received: by smtp.kernel.org (Postfix) with ESMTPSA id C6ED71F000C1; Tue, 3 Nov 2026 08:57:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793696259; bh=oMhmyIHQITW8+f0NpI/j7JCrVNR2HsEBSFaVwzb1ERI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=W05LwyrAb3oaQsjoWDhdx5HiqbPZW6kfF1ZpI/qZwVC8H1dvJK30UBtYkFsLUCoAA hiADN/LimuY2M6JYvSiqrsE70W69EvvgyTpAYN/Xjq7Fm4HJZTPIMMAktdyREhTLs1 tvju0K6xFw7S9w/sCxA76strVF8QS4+dNK9UXJpZxLvEY50HwtOx3zzEgQZCd9Niqw BQdDw1lQEUjnFr4TBiZ84e4ylZGNz20ovuEkaOsfn3I3tFIXq/GihIhp6MTHm6RxUh i3vHqJ6zC5uN/wt7ui1GSx7BUfL5C+qhK4jRv/fp63YZb3ZiZ5+O/5lhWPpBQGCP/H j6jBccRByLsow== From: Geliang Tang To: mptcp@lists.linux.dev Cc: Geliang Tang , Paolo Abeni Subject: [PATCH mptcp-next v20 6/6] mptcp: defer read_sock cleanup to mptcp_worker Date: Tue, 3 Nov 2026 16:57:25 +0800 Message-ID: <278ffcf759c109e3753112e62cb7c53b58159650.1793695518.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: Geliang Tang When MPTCP carries TLS, __mptcp_read_sock() may be 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. Conditionally defer cleanup to mptcp_worker(): when the caller doesn't own the socket lock (BH context), accumulate consumed bytes in msk->read_copied and signal the worker through MPTCP_WORK_READ_COMPLETE. When the caller owns the lock (process context), perform inline cleanup to avoid delaying window updates and autotuning. Replace msk_owned_by_me() assertion with DEBUG_NET_WARN_ON_ONCE using lockdep_sock_is_held() to verify proper locking for both process and BH contexts. Also remove the backlog flush from mptcp_recv_skb() (covered by mptcp_release_cb()) 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(). Suggested-by: Paolo Abeni Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 41 +++++++++++++++++++++++++++++++++-------- net/mptcp/protocol.h | 2 ++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 3e10b06b7772..25f0d10373d2 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3156,6 +3156,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; @@ -3231,6 +3246,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); @@ -3274,6 +3292,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); @@ -3721,6 +3740,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) msk->fastclosing =3D 0; msk->tfo_iasn =3D 0; msk->rcvd_dummy_seq =3D false; + msk->read_copied =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ @@ -4643,9 +4663,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) { @@ -4660,6 +4677,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) @@ -4669,7 +4687,7 @@ 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); + DEBUG_NET_WARN_ON_ONCE(!lockdep_sock_is_held(sk)); =20 if (sk->sk_state =3D=3D TCP_LISTEN) return -ENOTCONN; @@ -4701,11 +4719,18 @@ static int __mptcp_read_sock(struct sock *sk, read_= descriptor_t *desc, if (noack) goto out; =20 - mptcp_rcv_space_adjust(msk, copied); - if (copied > 0) { - mptcp_recv_skb(sk, &offset); - mptcp_cleanup_rbuf(msk, copied); + if (sock_owned_by_user(sk)) { + /* Process context: inline cleanup */ + mptcp_rcv_space_adjust(msk, copied); + mptcp_recv_skb(sk, &offset); + mptcp_cleanup_rbuf(msk, copied); + } else { + /* BH context: defer to worker */ + 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 fa54f70ab501..3580cf66f303 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; u64 tfo_iasn; --=20 2.55.0