From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 94A8C364E98 for ; Wed, 30 Sep 2026 02:25:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735120; cv=none; b=us19Ng/FflrfT17amdsLogACCtiqjdijMEuVySEO9RqQRU0XhkqbG54NpBtiO3FEP32+XB1AN2Urju0bhwunC5r4OgLuM61+XE67gfXgLv/F/NNLe+s5w79tCCo8B0MFCIKNbjwVVQNmVKHqH2MLd/gBc4H6BYmyoT0GA09Va+E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735120; c=relaxed/simple; bh=XVVfv2avOnpLIxFhSSit3o5m50O+F46VNiCaFjBJGo0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=az0Twl6TqgjnyYxTsbHc4SN/zp4+ve6Z7iMjRb3w7xKz4DXeXFzVGLRscN0Owo5E66fhc07DrkLOfNV85hcLHq/vXxUscZntT2bVKfeUEfh9dzO/ZkIuo5bJA7ydQKKc7xJGSLjpwXamCkOXiHT0UWPm5ZC65Cqnd4N7plT/FY4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HXSivPUV; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HXSivPUV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7AA261F00893; Wed, 30 Sep 2026 02:25:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735119; bh=BLHZ1RRLnNERGI/NOYQJGA20MX/rMUCM90TRpGZSORk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=HXSivPUVGSRIj1bgr2Yb9EcUK9m1UMJ6MFeYERbge2K/7xgfc/tdnI1E8V5BYkZLl u+iKOd/WNHhkip4w2aG+WF2o8wkjF/dODcCe3oss8KylWbfYmTI+RJxlze45gUJalc 14xIlI6sHX5sagsfLckPL8BBYJwJIVfyO2qHZXjl8sZKByoCPvxcJa5Tli+ZZuNh+a yXuuVGpzjbvPIwjAm06sS+7it1Kul6uCLO3C0WcbPSufOPKxzH71ZsQspYTW+abJVG eMkfGS+HFUF3VyPjjJ0BeSFrQeVXNGxSIuGKqF3WOCSWNieLuq7oy8emxCvO2CCITD MfhOwXS4GUvcw== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 01/11] mptcp: drop the mptcp_ooo_try_coalesce() helper Date: Wed, 30 Sep 2026 10:23:35 +0800 Message-ID: <3eefe25197c0d36afe02fcf674d754d4f7a3f353.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni 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 09779428e9ea..dcb3ba098702 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.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B87F136680E for ; Wed, 30 Sep 2026 02:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735139; cv=none; b=LaoAGeyNpblr8sHAG6LGe4U0qWCd06+fIMGFnFTBo7CelvUk4+VaQZmVNzaC4bUycJMczdRzSW3iZmVFHkqFKx1UPbfoMBonfV32IuXoB/ylBl7naiFC3aVG/PtAVKKRT+/kDOVUSlm3U/4M5GckeP/U5PpgRzrotbsuKqfwMuU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735139; c=relaxed/simple; bh=cUQEbX3DFv7WjPWFWqe3LxF+Qkn3uyRmqf3MLP0e+gE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CPxGNsZCNLban/IjZr40u24xozGEwj4E92nZbLOH2cWZ9r1MRRjN9dxeB8X3lsxW+5CU9czAOowNmiWifsuvAN6dLlo25Ap67QRzNyvyF1J709/uiFYrl/Y67W6ZkDnO3c6HVobci4aGrHmabApmEX5GA0wTpiID7376c0sEStc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mVA4grf+; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mVA4grf+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 110A51F000FF; Wed, 30 Sep 2026 02:25:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735137; bh=OT1NhVM1rCW4x3rGnsb6phyZBE8ieXZ6FwbSPdYzGlo=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mVA4grf+hfvAEVkPwb4sMlgCTiuaLMaduPwa4nNDbBhz1hOdkgWGoLdp8hJeT+NaI WGOcHGy1zo22qP32Mp/GMiiWvN2Y4eN+FM0W+wtuSwcp4/62p0aBEW51XXfCoKGwMj 0dM2Pu/NjXU+zIu9wOWqj2FyNg3EGtdYQSEdWMKto9XKi6yN0nDufLlDXH967HacsS UbKkqL8BUu6/pNIhBlUX8ELedROln9JPWu0H4p4bxjeHE3Ll7VJSZTLyy8tSFSXcHP B9CdZajxE1gZ//JEz8X28OO0Z+XPbmB8jEvNygOrxn1LebWGNZZUykn7qA7vzyDUga HiDgCkt31PyIg== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 02/11] mptcp: drop the cant_coalesce CB field Date: Wed, 30 Sep 2026 10:23:36 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni Such field is used to ensure in-sequence processing in case of fastopen. Instead let's perform synchronization of the fastopen skb sequence when the IASN becomes available with the 3rd ack. When the `cant_coalesce` field has been introduced, commit f03afb3aeb9d ("mptcp: drop __mptcp_fastopen_gen_msk_ackseq()") noted that updating the already queued skb for passive fastopen socket at 3rd ack time would be difficult and race prone. The main point is that such update don't need to be synchronously performed at 3rd ack time, but is sufficient to perform it before the next segment is introduced into the msk. To such extent, add an explicit test in __mptcp_move_skb(). Performance wise this trades a conditional in the fast path - in __mptcp_try_coalesce() - with a similar one in __mptcp_move_skb() and a couple more in slow paths. After this change the user-space will always observe consistent sequence numbers in the receive queue, even in the TFO dummy mapping case. Also add locking in mptcp_inq_hint() to avoid races with ack_seq updates during the fastopen sequence synchronization. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 6 +++-- net/mptcp/protocol.c | 57 ++++++++++++++++++++++++++++++++++++++++---- net/mptcp/protocol.h | 4 +++- net/mptcp/subflow.c | 10 ++++++++ 4 files changed, 69 insertions(+), 8 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 dcb3ba098702..1d3f29240387 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -29,7 +29,7 @@ #include "protocol.h" #include "mib.h" =20 -static unsigned int mptcp_inq_hint(const struct sock *sk); +static unsigned int mptcp_inq_hint(struct sock *sk); =20 #define CREATE_TRACE_POINTS #include @@ -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,27 @@ static void mptcp_init_skb(struct sock *ssk, struct sk= _buff *skb, int offset, skb_dst_drop(skb); } =20 +/* Caller must hold the msk data lock */ +void __mptcp_sync_rcv_sequence(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct sk_buff *skb; + u32 offset; + + if (likely(!msk->rcvd_dummy_seq)) + return; + + /* User space can have already received the TFO skb. */ + msk->rcvd_dummy_seq =3D false; + skb =3D skb_peek_tail(&sk->sk_receive_queue); + if (!skb) + return; + + offset =3D MPTCP_SKB_CB(skb)->offset; + MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len + offset; + MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -446,6 +465,19 @@ static bool __mptcp_move_skb(struct sock *sk, struct s= k_buff *skb) =20 mptcp_borrow_fwdmem(sk, skb); =20 + if (test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + /* Ensure we see the updated ack_seq after seeing the flag */ + smp_rmb(); + + mptcp_data_lock(sk); + /* 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); + mptcp_data_unlock(sk); + } + if (MPTCP_SKB_CB(skb)->map_seq =3D=3D msk->ack_seq) { /* in sequence */ insert: @@ -2383,15 +2415,23 @@ static bool mptcp_move_skbs(struct sock *sk) return enqueued; } =20 -static unsigned int mptcp_inq_hint(const struct sock *sk) +static unsigned int mptcp_inq_hint(struct sock *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); const struct sk_buff *skb; + 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; + /* Avoid races vs ack_seq updates and MPTCP_SYNC_SEQ flag. */ + mptcp_data_lock(sk); + if (test_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + mptcp_data_unlock(sk); + return 0; + } =20 + hint_val =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + mptcp_data_unlock(sk); if (hint_val >=3D INT_MAX) return INT_MAX; =20 @@ -3903,6 +3943,13 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); + if (test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + /* Ensure we see the updated ack_seq after seeing + * the flag + */ + smp_rmb(); + __mptcp_sync_rcv_sequence(sk); + } } } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 4bf04f9ecbd9..cfc86d00ab2f 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])) @@ -327,6 +327,7 @@ struct mptcp_sock { u32 token; unsigned long flags; unsigned long cb_flags; + bool rcvd_dummy_seq; bool recovery; /* closing subflow write queue reinjected */ bool can_ack; bool fully_established; @@ -1187,6 +1188,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 14aa82647c3d..807f6c5bbcf8 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -480,6 +480,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 */ @@ -498,6 +500,14 @@ static void subflow_set_remote_key(struct mptcp_sock *= msk, WRITE_ONCE(msk->ack_seq, subflow->iasn); WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); + + if (!sock_owned_by_user(sk)) { + __mptcp_sync_rcv_sequence(sk); + } else { + /* Ensure ack_seq is visible before setting the flag */ + smp_wmb(); + set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); + } } =20 static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D4E0343D7F for ; Wed, 30 Sep 2026 02:27:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735256; cv=none; b=hOlwjYOaAkjN7UeP2+snOIiEVT5idWfviGppGmgitPC9BKln3VXo9UxHWlF5ZJ+EymJIngvJUOISyDWYzNU2QaovY2eFhkgF4LPEJHpswbLr6fjj2yrd9fCvsDbEhO5+sVDX6CgphtNd1XDNizsa4pJNA/F7V+CUqe8pckGiaEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735256; c=relaxed/simple; bh=guIeGsmZJGW5h/qpnpoYlkPq+cs5pQg+Jt/COeLvD3A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=b6/7NfOHgqRl29rAmTb7epcflEtQL6XD2UQmtolLm/w1v69wpTeCYWddUE48XNP/ZH5yFP/jVZLUVMauPJQwild5MWVcZoi9fhiIvSz5te0PW2xFL1oGQe78hlyUXGq/OauvH7daGNcwReBjOy9KOH5Yhw8rvSu3zmXudfYd3Dc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IP8sDhnS; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IP8sDhnS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EF9AD1F00893; Wed, 30 Sep 2026 02:25:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735254; bh=41R4zdq+2+Ak+KiRmi/+iaxDVZWHV5u47n/YMdIY0aA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=IP8sDhnS+B5c+E5tupe9EY0UfjJ0tdj/AQ6D8u4KkZF0FNaoysl4S6YyddzSuzTVO uZE4AQTWtpDsuD0qn+jQYdGB+keWM+qV/V4FmBCSMxbBRh+O7BVUGjgbdNx+SGSwjw 6IYc11dcblxhPAHc4uEE/M06ZpCh69IEt05P84CasKquw9taPeSm8zRap+zqvGkP3q DsApYWcEsbySvq8BUfOBjc2d/1/i49Bfy46qDusPR/6yFFJ/E4cXbJdztQo2dowVue Epom0+W1TFwlJZ9ZIhTPGdXMEIN0+zwXJaE/gSoESPE6oJr4u/7Jh0thnBtfbWVAnw i05OYjPtmWqoQ== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 03/11] mptcp: remove CB offset field Date: Wed, 30 Sep 2026 10:23:37 +0800 Message-ID: <204c34dd358a267a7cf38fdae211120e25895c9d.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni Instead, use a new msk-level field to track the bytes already consumed inside each skb, carrying the amount of bytes already copied to user-space, alike what TCP is already doing. The newly introduce `copied_seq` field is always accessed under the msk socket lock, delegating the synchronization with IASN to the msk release CB, when the socket is owned by the user-space at remote key reception time. Such synchronization preserves any partial progress (copy) made on the TFO packet. Note that the explicit synchronization in __mptcp_move_skb() is needed to ensure that the TFO skb in the receive queue got its map_seq synched before the next skb lands into the receive queue when spooling the backlog at mptcp_release_cb() time, as the release CB synchronization will happen later. Prior to this patch, the TFO skb dummy mapping was always ignored, now it affects the `copied_seq` initial update: be sure to extends the sign correctly of such mapping initialization time. Overall this simplify a bit the __mptcp_recvmsg_mskq(), mptcp_inq_hint() and the __mptcp_move_skb() code and will also make possible the next patch. 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. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 9 ++-- net/mptcp/protocol.c | 115 +++++++++++++++++++------------------------ net/mptcp/protocol.h | 8 ++- net/mptcp/subflow.c | 10 ++++ 4 files changed, 74 insertions(+), 68 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index e18b31028e7e..421a50a85547 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -45,10 +45,11 @@ void mptcp_fastopen_subflow_synack_set_params(struct mp= tcp_subflow_context *subf subflow->ssn_offset +=3D skb->len; has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; =20 - /* Only the sequence delta is relevant */ - MPTCP_SKB_CB(skb)->map_seq =3D -skb->len; + /* The TFO segment data sits before the IASN; before receiving + * the remote key, IASN is assumed being 0. + */ + MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; MPTCP_SKB_CB(skb)->end_seq =3D 0; - MPTCP_SKB_CB(skb)->offset =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); @@ -56,6 +57,8 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf =20 msk =3D mptcp_sk(sk); msk->rcvd_dummy_seq =3D true; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 1d3f29240387..845fcca361fa 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -168,7 +168,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struc= t sk_buff *to, int limit =3D READ_ONCE(sk->sk_rcvbuf); =20 if (MPTCP_SKB_CB(from)->map_seq !=3D MPTCP_SKB_CB(to)->end_seq || - MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) return false; @@ -415,8 +414,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) skb_set_owner_r(skb, sk); } =20 -static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et, - int copy_len) +static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offs= et) { struct mptcp_subflow_context *subflow =3D mptcp_subflow_ctx(ssk); bool has_rxtstamp =3D TCP_SKB_CB(skb)->has_rxtstamp; @@ -425,9 +423,9 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_= buff *skb, int offset, * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq * value */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow); - MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + copy_len; - MPTCP_SKB_CB(skb)->offset =3D offset; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -441,7 +439,6 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *skb; - u32 offset; =20 if (likely(!msk->rcvd_dummy_seq)) return; @@ -452,9 +449,8 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - offset =3D MPTCP_SKB_CB(skb)->offset; - MPTCP_SKB_CB(skb)->map_seq =3D msk->ack_seq - skb->len + offset; - MPTCP_SKB_CB(skb)->end_seq =3D msk->ack_seq; + MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) @@ -470,6 +466,8 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) smp_rmb(); =20 mptcp_data_lock(sk); + msk->copied_seq +=3D mptcp_iasn(msk); + /* Be sure to sync the eventual fastopen dummy mapping before * any other skb lands into the msk. */ @@ -504,10 +502,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 @@ -865,7 +859,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); @@ -926,14 +920,9 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) end_seq =3D MPTCP_SKB_CB(skb)->end_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; - - /* 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; + (int)(msk->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; @@ -2210,33 +2199,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); @@ -2255,14 +2235,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 { @@ -2418,30 +2396,25 @@ static bool mptcp_move_skbs(struct sock *sk) static unsigned int mptcp_inq_hint(struct sock *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); - const struct sk_buff *skb; u64 hint_val; =20 - skb =3D skb_peek(&sk->sk_receive_queue); - if (skb) { - /* Avoid races vs ack_seq updates and MPTCP_SYNC_SEQ flag. */ - mptcp_data_lock(sk); - if (test_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { - mptcp_data_unlock(sk); - return 0; - } - - hint_val =3D msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq; + /* Avoid races vs ack_seq updates and MPTCP_SYNC_SEQ flag. */ + mptcp_data_lock(sk); + if (test_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { mptcp_data_unlock(sk); - if (hint_val >=3D INT_MAX) - return INT_MAX; - - return (unsigned int)hint_val; + return 0; } =20 - if (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) + hint_val =3D msk->ack_seq - msk->copied_seq; + mptcp_data_unlock(sk); + if (hint_val >=3D INT_MAX) + return INT_MAX; + + if (!hint_val && + (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN))) return 1; =20 - return 0; + return (unsigned int)hint_val; } =20 static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, @@ -2450,6 +2423,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 @@ -2468,6 +2442,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; @@ -2477,7 +2456,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) @@ -2487,8 +2466,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() @@ -2532,6 +2514,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); @@ -3714,11 +3700,13 @@ static int mptcp_disconnect(struct sock *sk, int fl= ags) msk->bytes_retrans =3D 0; msk->rcvspace_init =3D 0; msk->fastclosing =3D 0; + msk->tfo_skb_len =3D 0; mptcp_init_rtt_est(msk); =20 /* for fallback's sake */ WRITE_ONCE(msk->ack_seq, 0); atomic64_set(&msk->rcv_wnd_sent, 0); + msk->copied_seq =3D 0; =20 WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); @@ -3948,6 +3936,7 @@ static void mptcp_release_cb(struct sock *sk) * the flag */ smp_rmb(); + msk->copied_seq +=3D mptcp_iasn(msk); __mptcp_sync_rcv_sequence(sk); } } @@ -4614,7 +4603,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; @@ -4656,11 +4645,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 cfc86d00ab2f..3b42c5e22acf 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 @@ -306,6 +305,7 @@ struct mptcp_sock { u64 bytes_sent; u64 snd_nxt; u64 bytes_received; + u64 copied_seq; u64 ack_seq; atomic64_t rcv_wnd_sent; u64 rcv_data_fin_seq; @@ -325,6 +325,7 @@ struct mptcp_sock { u32 last_ack_recv; unsigned long timer_ival; u32 token; + u32 tfo_skb_len; unsigned long flags; unsigned long cb_flags; bool rcvd_dummy_seq; @@ -880,6 +881,11 @@ struct sock *mptcp_subflow_get_retrans(struct mptcp_so= ck *msk); int mptcp_sched_get_send(struct mptcp_sock *msk); int mptcp_sched_get_retrans(struct mptcp_sock *msk); =20 +static inline u64 mptcp_iasn(const struct mptcp_sock *msk) +{ + return msk->ack_seq - msk->bytes_received + msk->tfo_skb_len; +} + static inline u64 mptcp_data_avail(const struct mptcp_sock *msk) { return READ_ONCE(msk->bytes_received) - READ_ONCE(msk->bytes_consumed); diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 807f6c5bbcf8..a8247f5fe3e0 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -502,6 +502,8 @@ static void subflow_set_remote_key(struct mptcp_sock *m= sk, atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); =20 if (!sock_owned_by_user(sk)) { + /* User space could have already read partially the TFO skb */ + msk->copied_seq +=3D subflow->iasn; __mptcp_sync_rcv_sequence(sk); } else { /* Ensure ack_seq is visible before setting the flag */ @@ -524,6 +526,14 @@ 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: initialize sequence space to 0 (no remote key) */ + subflow->map_seq =3D 0; + /* ensure mptcp_subflow_get_map_offset() returns 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)) { --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95F2F24293C for ; Wed, 30 Sep 2026 02:27:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735280; cv=none; b=Wb2EVJ6EuXUm+PUQ4wAtfreOVlzXrXa2FdcxA/arG5SV3C6LxdeQW0JjUqTHhcqg9A+Zr/i8CAiz+wYCUFPa8v7KLC75o6Bwcw5z75aLaE9VwdgOwOGHAT15xj266rZUk/fn8F3C+O62mMfvpCfkFpt1+xscF6HK72BDv8uuOB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735280; c=relaxed/simple; bh=7thxabiuf4cZdYOm0btOu4Dda2LqEeWsskZCTEwQdY4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fhn1ZI2Lhs3k5YnRdKG7aTKb1kEYRkvwmqpIHhM8XmJ0xoPBSiIlr4uzVwphbYqacYXoI3xZxZ3/QXOBsGgwLkdBr6hD4xYhDzciqsVtiV4fW2fk7QFBpPKxLPfLvDg+TKD0eIujJ3hts+fHnJK5kXnLuy7fNG0efuzU5iovdXQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Sc/KLnOA; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Sc/KLnOA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 433AC1F000FF; Wed, 30 Sep 2026 02:27:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735278; bh=YNwDrLvTNMoXxm5OWZXRHZ2hXujpmLlzgP8IO9SHi5g=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Sc/KLnOAxGXQu5DmBGntgYFRycTj9UtO4j20MxZRL8jPmIm+WzuWn/YuL3Nhv0ex9 Sz/YQkJqGEmwcZIC4TzeqY4hlky9hsCysesDic8mKhluM1bRQ+inWLYb6KAwkJVmdR OgMGQgzglOkU/SDj46NqW+HpMjb+EaNAVRRUqk9YA8xZjMq/1YGVBlFxcluZXgeVGF OFxEuI+muV6tLjOj/kvAiQ00cu83U71cFuX4GbBfGGA1dNlbC9ggeWNv/rj7vZ5CHx VvTriczo/Gj/nMMCmtIw4nlVeEuYXXn9yl6bZWPsCb1/ue/RbmlfSbPh0vC6hdazcd lVR0gRMQEaGTw== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 04/11] mptcp: sync mptcp skb cb layout with tcp one Date: Wed, 30 Sep 2026 10:23:38 +0800 Message-ID: <4c7fd9c53905068b446d76dd27b22c82d20c7a1f.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni The MPTCP protocol uses a significantly different CB layout WRT TCP, as it includes different information and use 64 bits for the sequence numbers. As the msk-level rcvbuf buffer size is limited by the core socket code the INT_MAX; after validating the incoming skb vs the current receive window, we can safely use 32 bits for MPTCP-level sequence number. This allow updating the MPTCP CB layout so that fields with a corresponding TCP-level data use the same area inside the CB itself. Add build time check to ensure the latter invariant. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/fastopen.c | 6 ++- net/mptcp/protocol.c | 87 +++++++++++++++++++++++++++----------------- net/mptcp/protocol.h | 7 +++- 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index 421a50a85547..0d339dd454f9 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -48,8 +48,10 @@ void mptcp_fastopen_subflow_synack_set_params(struct mpt= cp_subflow_context *subf /* The TFO segment data sits before the IASN; before receiving * the remote key, IASN is assumed being 0. */ - MPTCP_SKB_CB(skb)->map_seq =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D -(u64)skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D 0; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 mptcp_data_lock(sk); @@ -57,7 +59,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptc= p_subflow_context *subf =20 msk =3D mptcp_sk(sk); msk->rcvd_dummy_seq =3D true; - msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq; + msk->copied_seq =3D MPTCP_SKB_CB(skb)->map_seq64; msk->tfo_skb_len =3D skb->len; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 845fcca361fa..a4a21717867f 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,15 +303,19 @@ 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)); + /* Use the full sequence space to perform the admission checks, to + * protect vs possible wrap-arounds. + */ if (after64(end_seq, max_seq)) { /* out of window */ mptcp_drop(sk, skb); @@ -345,7 +351,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 +363,18 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *m= sk, struct sk_buff *skb) while (*p) { parent =3D *p; skb1 =3D rb_to_skb(parent); - if (before64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->map_seq)) { p =3D &parent->rb_left; continue; } - if (before64(seq, MPTCP_SKB_CB(skb1)->end_seq)) { - if (!after64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (before(seq, MPTCP_SKB_CB(skb1)->end_seq)) { + if (!after(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ mptcp_drop(sk, skb); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA); return; } - if (after64(seq, MPTCP_SKB_CB(skb1)->map_seq)) { + if (after(seq, MPTCP_SKB_CB(skb1)->map_seq)) { /* partial overlap: * | skb | * | skb1 | @@ -399,7 +405,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk= , struct sk_buff *skb) merge_right: /* Remove other segments covered by skb. */ while ((skb1 =3D skb_rb_next(skb)) !=3D NULL) { - if (before64(end_seq, MPTCP_SKB_CB(skb1)->end_seq)) + if (before((u32)end_seq, MPTCP_SKB_CB(skb1)->end_seq)) break; rb_erase(&skb1->rbnode, &msk->out_of_order_queue); mptcp_drop(sk, skb1); @@ -421,11 +427,13 @@ static void mptcp_init_skb(struct sock *ssk, struct s= k_buff *skb, int offset) =20 /* the skb map_seq accounts for the skb offset: * mptcp_subflow_get_mapped_dsn() is based on the current tp->copied_seq - * value + * value; note that end seq number is only available in 32bits format. */ - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_subflow_get_mapped_dsn(subflow) - - offset; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_subflow_get_mapped_dsn(subflow) - + offset; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; + MPTCP_SKB_CB(skb)->flags =3D 0; MPTCP_SKB_CB(skb)->has_rxtstamp =3D has_rxtstamp; =20 __skb_unlink(skb, &ssk->sk_receive_queue); @@ -449,13 +457,14 @@ void __mptcp_sync_rcv_sequence(struct sock *sk) if (!skb) return; =20 - MPTCP_SKB_CB(skb)->map_seq =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq64 =3D mptcp_iasn(msk) - skb->len; + MPTCP_SKB_CB(skb)->map_seq =3D (u32)MPTCP_SKB_CB(skb)->map_seq64; MPTCP_SKB_CB(skb)->end_seq =3D MPTCP_SKB_CB(skb)->map_seq + skb->len; } =20 static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { - u64 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; + u32 copy_len =3D MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; struct mptcp_sock *msk =3D mptcp_sk(sk); struct sk_buff *tail; =20 @@ -476,7 +485,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk= _buff *skb) mptcp_data_unlock(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)) { @@ -494,14 +503,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 @@ -896,37 +905,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)) { - pr_debug("uncoalesced seq=3D%llx ack seq=3D%llx delta=3D%d\n", - MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq, - (int)(msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq)); + 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; @@ -2208,7 +2217,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; @@ -4603,7 +4612,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; @@ -4854,11 +4863,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 3b42c5e22acf..0258b4462d80 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.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E72B624293C for ; Wed, 30 Sep 2026 02:28:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735310; cv=none; b=Z4oy0kWTUGOW8LggIZRhiAggdZU/1Vdm2Ex+9WVRqa891+tfzrPqAUH5AEelSba1c146jEZ/4VYr3VDVfl2kXEGWRnQfnljFc/G+i8ze1j3oL7tpJxo0FcbMSJzXGXWKJUdde82qZEc0YKCoo8bPlxCkHrIKb1xlncOjFp+9LPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735310; c=relaxed/simple; bh=kYt5EmgS5tB9hRaH+gq6QsSbOR0pp7+tH9DEWVMn9R0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gIt13UiakQ6bjc0cKgAguG62K8MX314GE+Ip9fMjXrWxpiRnGXZRIDo68wW/VBCTI6rizI7nPYIJ9Y09P2JOi96U3JOE+Lebvl1ZZwl5eylT5Vil/DaiZH4YvMOSDGU/NFofuZNA/Q+OVtUO9oiBIZwhxzkehKGI3Jyyx+fDgI4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XkpcpC5I; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XkpcpC5I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B639B1F00893; Wed, 30 Sep 2026 02:27:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735308; bh=wYhonrHrq4vf2WRtl92vOJSkPqu0Uv3AOyO0VlNKcic=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=XkpcpC5ITMBJTsljJ2oFkohCNj9MX7Kzf7w41cONAEkeHvZbsc/9KXeXqs5VEj1wg xdOecGfRP0QG/d6hXMTu9N2xZ5Gt38ntAa49YswPksH5PR9nY+zU8FYOCLgDT1a5u7 hGlB2XMZ7xOYUAWVXcBVPFVjh0Lfx/STKPDdzV8i3SFiNgmh9jK94CcoSe4ZPPnM1s GS0pvH0yTyfVC60309K2n7O6Acej9R4s7qdpLS58EUAdLPZBVgL/wE6U+yis6scb1b tzP9l1rNBwVtl4DohEdleBOd4VZx2Z17WKOTTLayz9hLrw6NDeVCVDu5p2juTDo8/Y 1FaQMAA8cnKbw== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 05/11] mptcp: defer read_sock cleanup to mptcp_worker Date: Wed, 30 Sep 2026 10:23:39 +0800 Message-ID: <1ce3c8d4b5fb4704bf81d1b9ee629a40f9ef67ec.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Paolo Abeni When MPTCP carries TLS, the data path runs under mptcp_data_lock(). Reaching sk->sk_data_ready(sk) synchronously ends up at tls_strp_check_rcv() -> mptcp_recv_skb() -> mptcp_move_skbs(), which calls mptcp_data_lock() on the same sk and recurses on sk_lock.slock. The TLS path is not the only constraint: before the mptcp_recv_skb() calls, the TLS code would also reach __mptcp_read_sock(), which calls mptcp_rcv_space_adjust() and mptcp_cleanup_rbuf(). Both require holding the msk socket lock in process context, while the mptcp/TLS caller is in BH scope. Fix this by deferring sk->sk_data_ready(sk) to mptcp_worker() via a new MPTCP_WORK_READ_COMPLETE bit, reusing the existing mptcp_schedule_work()/ mptcp_cancel_work() infrastructure. The wakeup bit is consumed after the SOCK_DEAD && TCP_CLOSE destroy branch, so a socket that reaches the destroy path drops the pending wakeup rather than running it post-free. Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 32 ++++++++++++++++++++++++-------- net/mptcp/protocol.h | 2 ++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a4a21717867f..58b48a8962cc 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3147,6 +3147,20 @@ 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); + mptcp_cleanup_rbuf(msk, read_copied); +} + static void mptcp_do_fastclose(struct sock *sk) { struct mptcp_subflow_context *subflow, *tmp; @@ -3222,6 +3236,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); @@ -4608,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; if (offset < skb->len) { @@ -4625,6 +4639,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) @@ -4634,8 +4649,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) { @@ -4666,11 +4679,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 the workers's release callback. + */ 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 0258b4462d80..2bf97e570d37 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -117,6 +117,7 @@ #define MPTCP_FALLBACK_DONE 2 #define MPTCP_WORK_CLOSE_SUBFLOW 3 #define MPTCP_RTX_ENABLED 4 +#define MPTCP_WORK_READ_COMPLETE 5 =20 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 @@ -326,6 +327,7 @@ struct mptcp_sock { u32 last_data_sent; u32 last_data_recv; u32 last_ack_recv; + int read_copied; unsigned long timer_ival; u32 token; u32 tfo_skb_len; --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1775C343D7F for ; Wed, 30 Sep 2026 02:28:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735315; cv=none; b=sn+6Z7YA31uQyBEnSopQiSelvJBA+4Pa5f3ISeFNrWF327haaMYR2k0362uHnIkUTUqrF5NL5W7lodTsvfimAnIQzKzbZ/iU5Cnv+de7t4gB1/71yxEGvUD9YNLU4+x+kJMa5/BojQyMb5CmOK36/tiq5hUgJRQEGWf2rso5QCQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735315; c=relaxed/simple; bh=xt5y35oxjJE8bXnEKsX/Dh09GaIMlNmHfrgDoDWzIpc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pNt5mIXq+gFCvZ7ZhYRnDMqIRod8q69G5LPb/bik18axt0PF35b5sqyqvtRVBCM52F0SheuPS9x22R92xLAVHQLU8+MUV+4Z19X6HC5iK6Cs+6OCYyzMdyVoJTPpTaN+FpyjeqDcx7MG3OEHorj0iiC2BnzDrEmx+l/qUaWLGqY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=l2SYMoGk; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="l2SYMoGk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF72E1F000FF; Wed, 30 Sep 2026 02:28:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735313; bh=HMsW6BZnvR7mMmYjFN5gwgWGxqCh8xqVHU5rI8islsA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=l2SYMoGkg7Q0m3INAC898ZDsr4H1LbbPJHbSys8AOPmCgEZjVWE+OrFDt7PKldbo3 a9Ejj91+EvsVSx56ZpcZ5YcOOdx3iQY2X1+uGXtLL5yu10EAWEqqySHqrgrXNiMKZi CP5OxWzxPhcH+nbvE+rszuebbv2urUNtka558KA0ZU5l6gAY1zZbwYXYzdoObQ38UM tQpGrA4X0mtybvk5G92h36hkpNLNwzYYAryNjIJC8k5mciGXAGwsqODkPtwsCY1caW LqUDIvOr2JrkRGl1lpc9Cs2q4QR8w6RMtNLvgB7I6Zmpc16gYszxKRvfOrS5wmtwTe wv2xC8npRTp9w== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang , Zqiang Subject: [PATCH mptcp-next v14 06/11] mptcp: align FIN handling with TCP via SOCK_DONE Date: Wed, 30 Sep 2026 10:23:40 +0800 Message-ID: <64ec5f3d886de8362ffea9c0cc173dd89487ef1d.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang TCP uses SOCK_DONE to mark FIN reception because RCV_SHUTDOWN alone is ambiguous: it is also set by RST (via SHUTDOWN_MASK) without an ack_seq increment. mptcp_inq_hint() used the latter as a proxy for "FIN pending", causing over-count and potentially returning 0 to peek_len() on a RST-while-data-queued socket, hanging TLS/BPF strparser consumers. Mirror tcp_fin()/tcp_disconnect() in MPTCP: - Set SOCK_DONE in mptcp_check_data_fin() next to RCV_SHUTDOWN, strictly tied to the ack_seq +=3D1 that counts the FIN byte. - Test SOCK_DONE in mptcp_inq_hint() and mptcp_recvmsg() so the FIONREAD/ recvmsg FIN-handling only fires on a real DATA_FIN. - Reset SOCK_DONE in mptcp_disconnect() to mirror tcp_disconnect(). Memory ordering: use smp_mb() in mptcp_check_data_fin() to order the SHUTDOWN, rcv_data_fin, and ack_seq writes before the non-atomic sock_set_flag(SOCK_DONE) and the subsequent atomic operations in mptcp_set_state()/mptcp_close_wake_up(). Pair it with smp_rmb() in mptcp_inq_hint() so a reader never sees SOCK_DONE=3D1 without the matching ack_seq +=3D1. smp_mb() is required (rather than reusing the existing smp_mb__before_atomic()) because sock_set_flag() uses __set_bit() which is non-atomic: on LoongArch smp_mb__before_atomic() is just a compiler fence and a CPU could reorder the SOCK_DONE store past it. Co-developed-by: Zqiang Signed-off-by: Zqiang Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 58b48a8962cc..7eafe904dbc6 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -741,7 +741,8 @@ static void mptcp_check_data_fin(struct sock *sk) WRITE_ONCE(msk->rcv_data_fin, 0); =20 WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | RCV_SHUTDOWN); - smp_mb__before_atomic(); /* SHUTDOWN must be visible first */ + smp_mb(); /* Order SHUTDOWN, ack_seq before SOCK_DONE. */ + sock_set_flag(sk, SOCK_DONE); =20 switch (sk->sk_state) { case TCP_ESTABLISHED: @@ -2405,8 +2406,12 @@ static bool mptcp_move_skbs(struct sock *sk) static unsigned int mptcp_inq_hint(struct sock *sk) { const struct mptcp_sock *msk =3D mptcp_sk(sk); + bool sock_done =3D sock_flag(sk, SOCK_DONE); u64 hint_val; =20 + /* Pair with smp_mb() in mptcp_check_data_fin(). */ + smp_rmb(); + /* Avoid races vs ack_seq updates and MPTCP_SYNC_SEQ flag. */ mptcp_data_lock(sk); if (test_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { @@ -2419,8 +2424,7 @@ static unsigned int mptcp_inq_hint(struct sock *sk) if (hint_val >=3D INT_MAX) return INT_MAX; =20 - if (!hint_val && - (sk->sk_state =3D=3D TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN))) + if (!hint_val && sock_done) return 1; =20 return (unsigned int)hint_val; @@ -2492,6 +2496,9 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, !timeo) break; } else { + if (sock_flag(sk, SOCK_DONE)) + break; + if (sk->sk_err) { copied =3D sock_error(sk); break; @@ -3735,6 +3742,7 @@ static int mptcp_disconnect(struct sock *sk, int flag= s) msk->copied_seq =3D 0; =20 WRITE_ONCE(sk->sk_shutdown, 0); + sock_reset_flag(sk, SOCK_DONE); sk_error_report(sk); return 0; } --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62902343D7F for ; Wed, 30 Sep 2026 02:28:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735317; cv=none; b=RTJcl0hhX6JtxQX7Qi69YgWUZpGaCqwe+T76Ebw+8f/6R5E+S9YLGKwgY7njyndRowVh6acbWTMNOUSy2KmS4+9E5bx5OGxWwTJTCf9GaPVbODlnxx9m96++NzQhgcDfTSVs9IdFzILioNGL2EINQd8zFi8m96lf9cnQQFTbUk4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735317; c=relaxed/simple; bh=zGERlKiHo4mFFzIf9inBHN2WnV1pkCsrohv+OxB/API=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NpkvmLARUokjgR6tNJq0CNcIfrGWVyhpC10wrR0O+Jkl6b45TjvC4mlFtRmJk7YuAlm+xIjn26VDAQZdwFNo/xMOaT3b0XKCmrLpXIhelgQYCIM+q62fI7SQoHwRdMFLVj5BaSLU1zgo712I8qsLrDDBOGP750vQF9JrYzNMEIg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Jw/V+m+n; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Jw/V+m+n" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 79DF91F00893; Wed, 30 Sep 2026 02:28:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735316; bh=fwPfJ4O2rdI2mGLvbd6W1LqHvu4M8E7KESGTc87qUpU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Jw/V+m+nQz/QK4tcZSr+Yh3RM+oZpf5l/qCRpVKFemDb7KusCgBpIBteLTotk42XN SD+uUyCJT57bq3YiJmX+gTnK3PLXxQe4QSc6IUwTYKGA1vgP4aQw4V2iwMbCbAbcDO 5kU2gx3l8a7hffcZeanfXWoTUUzfOTcA3l7Kw/ZmQIQwjiPlZIFlZ3KUX6eoQs4VgE iBvXOTFWIVCqe994uVK1ZkRKYyyVr21LX00uC+euQA3Gr3txjSalAsrXnVuwGTBRBG tNwqydIBxIUpaW5YJ7fcB9cRoEB38LoQlrZbj8RHv5nLNc6rABORpD/4eAFZlvFii3 ToSJPWI6fQhBQ== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang , Zqiang Subject: [PATCH mptcp-next v14 07/11] mptcp: implement peek_len for proto_ops Date: Wed, 30 Sep 2026 10:23:41 +0800 Message-ID: <3ccb18c2210da287ff7c13b9d28d85310e2b671e.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang Add mptcp_inq() to compute the number of readable bytes at the MPTCP level. It derives the count from ack_seq - copied_seq, returns 0 while the connection is still handshaking (TCP_SYN_SENT/TCP_SYN_RECV), and subtracts 1 once a FIN has been received, mirroring tcp_inq(). The subtraction is needed because MPTCP's ack_seq is incremented by 1 in mptcp_check_data_fin() when the DATA_FIN is processed, consuming a sequence number without carrying any payload data. Without subtracting 1, peek_len would over-report by one byte, causing upper layers to wait for data that will never arrive. READ_ONCE() is used instead of mptcp_data_lock() for the u64 reads of ack_seq and copied_seq because mptcp_inq() will be called from TLS contexts with the socket lock held - taking the spinlock would deadlock. On 32-bit systems a torn read can produce a wrapped subtraction (close to 2^64), which is caught by the INT_MAX clamp. TLS callers use mptcp_inq() conservatively: over-reporting defers work to the next iteration, where recvmsg() provides the actual byte count. Wire mptcp_inq() into mptcp_peek_len() and assign .peek_len in both mptcp_stream_ops and mptcp_v6_stream_ops, so upper layers get the correct in-queue byte count for MPTCP connections. Co-developed-by: Zqiang Signed-off-by: Zqiang Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7eafe904dbc6..84478bace0ab 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -4819,6 +4819,41 @@ static ssize_t mptcp_splice_read(struct socket *sock= , loff_t *ppos, return ret; } =20 +static int mptcp_inq(struct sock *sk) +{ + const struct mptcp_sock *msk =3D mptcp_sk(sk); + int answ; + + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { + answ =3D 0; + } else if (test_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) { + answ =3D 0; + } else { + bool sock_done =3D sock_flag(sk, SOCK_DONE); + u64 hint_val; + + /* Pair with smp_mb() in mptcp_check_data_fin(). */ + smp_rmb(); + + hint_val =3D READ_ONCE(msk->ack_seq) - READ_ONCE(msk->copied_seq); + if (hint_val >=3D INT_MAX) + hint_val =3D INT_MAX; + + answ =3D (unsigned int)hint_val; + + /* Subtract 1, if FIN was received. Mirror tcp_inq() */ + if (answ && sock_done) + answ--; + } + + return answ; +} + +static int mptcp_peek_len(struct socket *sock) +{ + return mptcp_inq(sock->sk); +} + static const struct proto_ops mptcp_stream_ops =3D { .family =3D PF_INET, .owner =3D THIS_MODULE, @@ -4841,6 +4876,7 @@ static const struct proto_ops mptcp_stream_ops =3D { .set_rcvlowat =3D mptcp_set_rcvlowat, .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, + .peek_len =3D mptcp_peek_len, }; =20 static struct inet_protosw mptcp_protosw =3D { @@ -4965,6 +5001,7 @@ static const struct proto_ops mptcp_v6_stream_ops =3D= { .set_rcvlowat =3D mptcp_set_rcvlowat, .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, + .peek_len =3D mptcp_peek_len, }; =20 static struct proto mptcp_v6_prot; --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83793343D7F for ; Wed, 30 Sep 2026 02:28:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735319; cv=none; b=GXymnME7tXpVw45Gq5S2mxG5vQIf/yeyvMxNRWpmY1lQFUmfEmvm83NmpyAqC30xkHLrSd2PMKydP0KWegYcQeTLqpH21Q/ZJ1k8QMhn1EOxpHOSi/dN9kYkqd66y1fO3bYKaGMQpQO5J1iHRZrpqGielyJro4fL/m6SuyQGVK0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735319; c=relaxed/simple; bh=dJZrfDdLb3oB8i8462pwur9aJJtTE1FN/cqQQndIbJo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=k5FjTfyN23+mwB7CVh+JyGU9vVgcUJ+zZSfhYMre0ePnL2X+NQn6Vm1FkWaBmxiaD84CDfZ4zEyNSnaHUjE51ioUfhMzg0FpNPU42/lzwbpJ2cBRZEiiXN+OcgZRH4L98LMQCZr+y+wb+EHD5tshA9MMyoe0myrXr2Fn3a4p43I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L1KE8QkT; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L1KE8QkT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E9CC21F000FF; Wed, 30 Sep 2026 02:28:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735318; bh=XyYHALBCJLBoigAJCfiubsqfrmLE1AI6hptc5h3Tq9U=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=L1KE8QkT5yw0XhrD70TJK4RbXzKJYqri62F1RybofZu3CloiqPlA3oHpeFfuBDdym TFylEhikfQ4KPi5vU+pbbW+cHTivGF/UwR55NpsiV3UGrbJqitxWjKW7aKq8A5zkGY Ek8m/L6rKql6gCC3YXXFzL5B/LyU1YKP8ELtGtXudPdidMRNoE+4GovUJElejgQRbs ZDZ9mPs5cKct+WmeFYyWYfdL2zQCJo1rw0M1Ovv50KSI5BmDb3C0g9j4pMu8Bc4Vsx 5W55tcMUCMocUfWYJWQFfavE0qHt82PtNP22W1FX0uyhvsNllvKeRS/drAC+GUY+zM 8s+e852tq8FaQ== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 08/11] mptcp: add sendmsg_locked to proto_ops Date: Wed, 30 Sep 2026 10:23:42 +0800 Message-ID: <36a2670793444666d78b4e197a28e2308f21b273.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang MPTCP currently provides a standard sendmsg() implementation which acquires and releases the socket lock internally. However, certain upper layers need to call the sendmsg method while the socket lock is already held. Split the existing mptcp_sendmsg() into mptcp_sendmsg_locked() which assumes the caller holds the socket lock, and a tiny wrapper mptcp_sendmsg() that acquires the lock and calls the locked version. Expose .sendmsg_locked in both mptcp_stream_ops and mptcp_v6_stream_ops. Signed-off-by: Geliang Tang --- net/mptcp/protocol.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 84478bace0ab..319339be8076 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2055,7 +2055,7 @@ static void mptcp_rps_record_subflows(const struct mp= tcp_sock *msk) } } =20 -static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_= t len) { struct mptcp_sock *msk =3D mptcp_sk(sk); struct page_frag *pfrag; @@ -2067,8 +2067,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) msg->msg_flags &=3D MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_FASTOPEN | MSG_EOR; =20 - lock_sock(sk); - mptcp_rps_record_subflows(msk); =20 if (unlikely(inet_test_bit(DEFER_CONNECT, sk) || @@ -2184,7 +2182,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msgh= dr *msg, size_t len) } =20 out: - release_sock(sk); return copied; =20 do_error: @@ -2195,6 +2192,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msg= hdr *msg, size_t len) goto out; } =20 +static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) +{ + int ret; + + lock_sock(sk); + ret =3D mptcp_sendmsg_locked(sk, msg, len); + release_sock(sk); + + return ret; +} + static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied); =20 static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb) @@ -4877,6 +4885,7 @@ static const struct proto_ops mptcp_stream_ops =3D { .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, .peek_len =3D mptcp_peek_len, + .sendmsg_locked =3D mptcp_sendmsg_locked, }; =20 static struct inet_protosw mptcp_protosw =3D { @@ -5002,6 +5011,7 @@ static const struct proto_ops mptcp_v6_stream_ops =3D= { .read_sock =3D mptcp_read_sock, .splice_read =3D mptcp_splice_read, .peek_len =3D mptcp_peek_len, + .sendmsg_locked =3D mptcp_sendmsg_locked, }; =20 static struct proto mptcp_v6_prot; --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48098343D7F for ; Wed, 30 Sep 2026 02:28:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735321; cv=none; b=APUHfa4XN5qNZJL0ZgupJpRukzdylXEveNORJHYplOOodcvpwpbwcXLA/lnprCXjqC75IGmmOA7i4meY9pe6mTb+WxUE0o7IFKITaFOOiFe9ywTE1VoPkcoVF7Kc/dt2/jIj8oLKiYp18EnnlxuNEt4x3VtAluMzLUKluUu7Ipo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735321; c=relaxed/simple; bh=jWr2zxCZdHB+8ydFyIwTXdKjC0HMANmCT0RKBw66FNg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dZ+NSlrAp6baOPfhKnMycqcxc7Z3sA/jxcRh9WxNzooCUhOHkuofo9BEzQ+ZEaKsY3+eK3XkNUVCnnm9GiAM0as0TjvuensCp2bMDfibgqsf0dJw5wzKbL9QV6Jah/6Hg1pPdYpVouwGH65L61rEcTq11x6AUWJ1mlWCBWHBn+w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BGT++j4P; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BGT++j4P" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5AEC1F00893; Wed, 30 Sep 2026 02:28:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735320; bh=uaukxXp96mEKIf3TNQz1To8T1h+WXdqLsHopIocJ9AQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BGT++j4PH3kpqFWvPI1MRjno7pTyLcJ5kyqbBvzYMJYyf0pPqxbkHU+/3O1ceV0s6 NLdsBQs6yOMas//MupHihZzxHm88QMwDhDzqz3rlpHWcErTbtiJntS+CcEhcvSdjzx jWulDD6Wjsi9VvCQNpdcDPDFezRT10U1/WKdocvvT5EEfT9XIIcol3DWqVg5od7H5P PuGoEKk63l+eQ+9YWBLn4sIqHU1YIDUDNz4lVk2PlVw2GATZDKVyZWtH9AMHC/7CKF j1kzuGf4lMjFp1FTdQeD/CCQT8apbdOfGuVJ83oTWx5u887JB9w1Ap9YHVQczklHIf kWaCDruzLbwQw== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 09/11] mptcp: track app-limited state in mptcp_sendmsg Date: Wed, 30 Sep 2026 10:23:43 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang The application-limited accounting in TCP is updated by tcp_rate_check_app_limited(), which currently takes a struct sock * and internally calls tcp_sk(). MPTCP needs to apply the same accounting to each subflow individually - every subflow is an independent TCP socket with its own tp->app_limited / delivered state - so wrapping the call as a struct sock * -> tcp_sk() helper is awkward at the call site. Split the existing function: keep the logic as tcp_sock_rate_check_app_limited(struct tcp_sock *tp), and turn tcp_rate_check_app_limited(struct sock *) into a thin wrapper so the exported API is unchanged for other TCP users. Then add mptcp_sock_rate_check_app_limited() that walks every subflow of the mptcp_sock and runs tcp_sock_rate_check_app_limited() under each subflow's socket lock. Invoke it from mptcp_sendmsg() right after the send-side setup, so the delivery-rate app_limited state stays in sync with what the application actually has to send across each subflow. With this in place, TCP_INFO.tcpi_delivery_rate_app_limited is reported correctly for MPTCP connections instead of being left at 0. Signed-off-by: Geliang Tang --- include/net/tcp.h | 1 + net/ipv4/tcp.c | 9 +++++++-- net/mptcp/protocol.c | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 96a1a23e47fa..7188f9ec3864 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -851,6 +851,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock= *tp, int pktsize) =20 /* tcp.c */ void tcp_get_info(struct sock *, struct tcp_info *); +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp); void tcp_rate_check_app_limited(struct sock *sk); =20 /* Read 'sendfile()'-style from a TCP socket */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5d374053e903..0b41befbbf4f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1099,9 +1099,9 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msgh= dr *msg, int *copied, } =20 /* If a gap is detected between sends, mark the socket application-limited= . */ -void tcp_rate_check_app_limited(struct sock *sk) +void tcp_sock_rate_check_app_limited(struct tcp_sock *tp) { - struct tcp_sock *tp =3D tcp_sk(sk); + struct sock *sk =3D (struct sock *)tp; =20 if (/* We have less than one packet to send. */ tp->write_seq - tp->snd_nxt < tp->mss_cache && @@ -1114,6 +1114,11 @@ void tcp_rate_check_app_limited(struct sock *sk) tp->app_limited =3D (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; } + +void tcp_rate_check_app_limited(struct sock *sk) +{ + tcp_sock_rate_check_app_limited(tcp_sk(sk)); +} EXPORT_SYMBOL_GPL(tcp_rate_check_app_limited); =20 int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 319339be8076..1f7aaf3214a0 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2055,6 +2055,21 @@ static void mptcp_rps_record_subflows(const struct m= ptcp_sock *msk) } } =20 +static void mptcp_rate_check_app_limited(struct sock *sk) +{ + struct mptcp_sock *msk =3D mptcp_sk(sk); + struct mptcp_subflow_context *subflow; + + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); + bool slow; + + slow =3D lock_sock_fast_nested(ssk); + tcp_sock_rate_check_app_limited(tcp_sk(ssk)); + unlock_sock_fast(ssk, slow); + } +} + static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_= t len) { struct mptcp_sock *msk =3D mptcp_sk(sk); @@ -2083,6 +2098,9 @@ static int mptcp_sendmsg_locked(struct sock *sk, stru= ct msghdr *msg, size_t len) =20 timeo =3D sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); =20 + /* is sending application-limited? */ + mptcp_rate_check_app_limited(sk); + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { ret =3D sk_stream_wait_connect(sk, &timeo); if (ret) --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53FAB36CDE0 for ; Wed, 30 Sep 2026 02:28:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735323; cv=none; b=XGzjLzOavlG73MyxLIklcEs9k3qSe/GThXS27MDxYFhprmFptSjD+ATFl1vQnX94dbaI8VK0x6oM3igLYnWSdjj73ivSf5+reD37xHq5gDUtjlbw1UoEKvM6rvOzUJkmmS44/Zw5i5fakbic1R1SE3qfIZfmXu9VAe94vYQGoYQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735323; c=relaxed/simple; bh=JxT3qeiSHuBS12KtGnTPLFRzVxKd0fvCXwqrRkI3nnM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n/RQfI53mB7NvENRRfKqhpCRLHNEqRwO04MlnKFHk66yAcye1aMPwYC88sYVnLLZf+X583EMfJ16RnrIpB6TzFz1bFRqyx4u14N61ZMRML31ovCcMvP/geDbpBpA/fKScGJUZGoS2n7Ci0843pnBGLgqNlWUVHv7l9heF8iWeeo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IBgXsSo4; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IBgXsSo4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CF37D1F000FF; Wed, 30 Sep 2026 02:28:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735322; bh=xNNDwMcimuhvgxiiYj/oGzahS6NB1VtBfCB7+LyvfjA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=IBgXsSo43cY5Q0GmcUMDCL4y83siN3Kx0Nfhe+pmiO1PmeHTCAhr2i17r1ex4n1TF KP8pelzo+uDlLk2vTuvQDtbuVIOxRuiNKd6NPIlnCL7OH73upc70CKFszvBBmt66pY E+fCFbqA5njvETElPxDvJN6JzeWVN1olubzuGJWyGeVVC4W3UHBuf3iu1suMRAkuiC uZUGOp31BEvB/LupIF5ObqyhYEkgKX6Wld6UkfQhFekKUt+CEggNclW2xsk0yEMjBL 1KBBo7qC9eiwlLlwV5jLJExDNTP2XhhaNQEN9LvSHS7vCfHVzgG9fQDPl4eCbX3Gue QfgQ/vI/vPdew== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Geliang Tang Subject: [PATCH mptcp-next v14 10/11] selftests: mptcp: sockopt: check app_limited Date: Wed, 30 Sep 2026 10:23:44 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Geliang Tang connect_one_server() in mptcp_sockopt exchanges only a few packets between the client and server, then closes the socket. After such a small transfer the application has nothing further to send, so the connection is, by definition, application-limited. Extend the TCP_INFO readback at the end of the function to assert s.tcp_info.tcpi_delivery_rate_app_limited =3D=3D 1. Without the preceding commit, mptcp_sendmsg() never updates the per-subflow app-limited state, and this field stays at 0 - the assertion would fail. With it in place, the value is forced to 1, turning this into a regression guard for the subflow-side application-limited accounting. Signed-off-by: Geliang Tang --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/test= ing/selftests/net/mptcp/mptcp_sockopt.c index d68515b7903b..8d712bdb4325 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -640,6 +640,7 @@ static void connect_one_server(int fd, int pipefd) total +=3D 1; /* sequence advances due to FIN */ =20 assert(s.mptcpi_rcv_delta =3D=3D (uint64_t)total); + assert(s.tcp_info.tcpi_delivery_rate_app_limited =3D=3D 1); close(fd); } =20 --=20 2.53.0 From nobody Thu Oct 15 23:34:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C395735C6B6 for ; Wed, 30 Sep 2026 02:28:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735328; cv=none; b=bNZlA/cvm96eTumnHC3XIvW+lv//3BfRW0t+Tl6iB+7+diqIJbCv7RlbAOrZ9/akSxhUfkcP0L1cgnO5DZrBrpgHwjdNGf9OAJw2jNYu7x6biy90C/6ZScsGgCNFB+1t1rCFlk56tKDS3v8Dn4s/AaxYWfypNsTHWrGVpYiwxyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790735328; c=relaxed/simple; bh=YcsamNNamtCUvUCR/SxqL74eb+lj/rWrYG/T1qLlr/s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Om54dhOTASS5lwK4TZOvtFkXn8WSSG+OI4LVm5BIRu/7+W6zs4XHCqC4iymP1QNC7ObsZMZzBoPU+O/73oAXLiTeApbD8ILQtSGW3QsgUs0ce/5u4DMAouIVEc4+rnNDa+1cOqw8EP42g1EWZ6jC9iqLyXo8r8Vyw+YzGOAHSn4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=izqRNQxg; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="izqRNQxg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DAB911F00893; Wed, 30 Sep 2026 02:28:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790735324; bh=bW+AcfyhqKTqDRhejnqAWmE6GuP2Mfw45SAo6ETKxRI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=izqRNQxgx0fCjswvda7GF3mZXzWWHJnU5rl57QONoXgHvoRrOrZOrPdfWjxByuEsX ybh5LOd0c/DA6lw3GfRbgnisZXqwGC95zcfkxyp00YRJjbl1ctyKxVwFbTunSQR+id L82aXInBWD85os8Rgl67GLAnioGOo7+DmWSv051h73vL3cXDoJUup34rl8Wq2r6aCa i5CdH+oFzegRdkD+qBjE+C1X32ZfwcqH+VjZcpxbw2CMNrGsQ+fKXAUbePWcnzxLUt +ARcbwaGM+ac2smHT2GO40JCBkl68DyiVWe4s1WrhLGHqE/icYErB0GMg08MnpobJT Lv2E2+1LSSrBw== From: Geliang Tang To: mptcp@lists.linux.dev, pabeni@redhat.com Cc: Gang Yan , Geliang Tang Subject: [PATCH mptcp-next v14 11/11] mptcp: update mptcp_check_readable Date: Wed, 30 Sep 2026 10:23:45 +0800 Message-ID: <0b914bfd521e1e6eda15f8ba7124cfd5342bb596.1790734083.git.tanggeliang@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan This patch makes mptcp_check_readable() aligned with TCP, and renames it to mptcp_stream_is_readable(). It will be used in the case of KTLS, because 'prot' will be modified, tls_sw_sock_is_readable() is expected to be called from prot->sock_is_readable(). Co-developed-by: Geliang Tang Signed-off-by: Geliang Tang Signed-off-by: Gang Yan --- net/mptcp/protocol.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 1f7aaf3214a0..dac1659bbb19 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3546,9 +3546,11 @@ void __mptcp_unaccepted_force_close(struct sock *sk) __mptcp_destroy_sock(sk); } =20 -static __poll_t mptcp_check_readable(struct sock *sk) +static bool mptcp_stream_is_readable(struct sock *sk) { - return mptcp_epollin_ready(sk) ? EPOLLIN | EPOLLRDNORM : 0; + if (mptcp_epollin_ready(sk)) + return true; + return sk_is_readable(sk); } =20 static void mptcp_check_listen_stop(struct sock *sk) @@ -4633,7 +4635,8 @@ static __poll_t mptcp_poll(struct file *file, struct = socket *sock, mask |=3D EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; =20 if (state !=3D TCP_SYN_SENT && state !=3D TCP_SYN_RECV) { - mask |=3D mptcp_check_readable(sk); + if (mptcp_stream_is_readable(sk)) + mask |=3D EPOLLIN | EPOLLRDNORM; if (shutdown & SEND_SHUTDOWN) mask |=3D EPOLLOUT | EPOLLWRNORM; else --=20 2.53.0