[PATCH mptcp-next 2/6] mptcp: drop the cant_coalesce CB field
Geliang Tang <[email protected]> Mon, 27 Jul 2026 19:29:17 +0800
| Newsgroups | dev.linux.lists.mptcp |
|---|---|
| Message-ID | <311dd7ed06e3e5cf600cafa747765d360f060b48.1785150300.git.tanggeliang@kylinos.cn> |
From: Paolo Abeni <[email protected]> Such field is used to ensure in-sequence processing in case of fastopen. Instead let's perform synchronization of the fastopen skb sequence when the IASN becomes available with the 3rd ack. When the `cant_coalesce` field has been introduced, commit f03afb3aeb9d ("mptcp: drop __mptcp_fastopen_gen_msk_ackseq()") noted that updating the already queued skb for passive fastopen socket at 3rd ack time would be difficult and race prone. The main point is that such update don't need to be synchronously performed at 3rd ack time, but is sufficient to perform it before the next segment is introduced into the msk. To such extent, add an explicit test in __mptcp_move_skb(). Performance wise this trades a conditional in the fast path - in __mptcp_try_coalesce() - with a similar one in __mptcp_move_skb() and a couple more in slow paths. After this change the user-space will always observe consistent sequence numbers in the receive queue, even in the TFO dummy mapping case. There is still a potential race in mptcp_inq_hint() that will be addressed by a later patch in the series. Signed-off-by: Paolo Abeni <[email protected]> --- net/mptcp/fastopen.c | 2 +- net/mptcp/protocol.c | 28 ++++++++++++++++++++++++++-- net/mptcp/protocol.h | 4 +++- net/mptcp/subflow.c | 7 +++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index f717750906ff..d6895c2200cc 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -49,11 +49,11 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf MPTCP_SKB_CB(skb)->end_seq = 0; MPTCP_SKB_CB(skb)->offset = 0; MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce = 1; mptcp_data_lock(sk); DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk)); + mptcp_sk(sk)->rcvd_dummy_seq = true; mptcp_borrow_fwdmem(sk, skb); skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->sk_receive_queue, skb); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index d7838ab334fd..c0b6e312816f 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -160,7 +160,6 @@ static bool __mptcp_try_coalesce(struct sock *sk, struct sk_buff *to, int limit = READ_ONCE(sk->sk_rcvbuf); if (MPTCP_SKB_CB(from)->map_seq != MPTCP_SKB_CB(to)->end_seq || - unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (limit >> 3)) || !skb_try_coalesce(to, from, fragstolen, delta)) @@ -357,7 +356,6 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset, MPTCP_SKB_CB(skb)->end_seq = MPTCP_SKB_CB(skb)->map_seq + copy_len; MPTCP_SKB_CB(skb)->offset = offset; MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; - MPTCP_SKB_CB(skb)->cant_coalesce = 0; __skb_unlink(skb, &ssk->sk_receive_queue); @@ -408,6 +406,24 @@ static bool mptcp_prune_ofo_queue(struct sock *sk, u64 seq) return mem <= sk->sk_rcvbuf; } +void __mptcp_sync_rcv_sequence(struct sock *sk) +{ + struct mptcp_sock *msk = 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 = false; + skb = skb_peek_tail(&sk->sk_receive_queue); + if (!skb) + return; + + MPTCP_SKB_CB(skb)->map_seq = msk->ack_seq - skb->len; + MPTCP_SKB_CB(skb)->end_seq = msk->ack_seq; +} + static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) { u64 copy_len = MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq; @@ -416,6 +432,12 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb) mptcp_borrow_fwdmem(sk, skb); + /* Be sure to sync the eventual fastopen dummy mapping before any other + * skb lands into the msk. + */ + if (unlikely(msk->rcvd_dummy_seq)) + __mptcp_sync_rcv_sequence(sk); + /* Can't drop packets for fallback socket this late, or the stream * will break. */ @@ -3833,6 +3855,8 @@ static void mptcp_release_cb(struct sock *sk) __mptcp_error_report(sk); if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags)) __mptcp_sync_sndbuf(sk); + if (__test_and_clear_bit(MPTCP_SYNC_SEQ, &msk->cb_flags)) + __mptcp_sync_rcv_sequence(sk); } } diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index da40c6f3705f..19b6eafece71 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -124,13 +124,13 @@ #define MPTCP_FLUSH_JOIN_LIST 5 #define MPTCP_SYNC_STATE 6 #define MPTCP_SYNC_SNDBUF 7 +#define MPTCP_SYNC_SEQ 8 struct mptcp_skb_cb { u64 map_seq; u64 end_seq; u32 offset; u8 has_rxtstamp; - u8 cant_coalesce; }; #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) @@ -310,6 +310,7 @@ struct mptcp_sock { u32 token; unsigned long flags; unsigned long cb_flags; + bool rcvd_dummy_seq; bool recovery; /* closing subflow write queue reinjected */ bool can_ack; bool fully_established; @@ -1169,6 +1170,7 @@ void mptcp_event_pm_listener(const struct sock *ssk, enum mptcp_event_type event); bool mptcp_userspace_pm_active(const struct mptcp_sock *msk); +void __mptcp_sync_rcv_sequence(struct sock *sk); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow, struct request_sock *req); int mptcp_pm_genl_fill_addr(struct sk_buff *msg, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 8e386899ceb9..ea9b697c0300 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -478,6 +478,8 @@ static void subflow_set_remote_key(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, const struct mptcp_options_received *mp_opt) { + struct sock *sk = (struct sock *)msk; + /* active MPC subflow will reach here multiple times: * at subflow_finish_connect() time and at 4th ack time */ @@ -496,6 +498,11 @@ static void subflow_set_remote_key(struct mptcp_sock *msk, WRITE_ONCE(msk->ack_seq, subflow->iasn); WRITE_ONCE(msk->can_ack, true); atomic64_set(&msk->rcv_wnd_sent, subflow->iasn); + + if (!sock_owned_by_user(sk)) + __mptcp_sync_rcv_sequence(sk); + else + __set_bit(MPTCP_SYNC_SEQ, &msk->cb_flags); } static void mptcp_propagate_state(struct sock *sk, struct sock *ssk, -- 2.53.0