From: sashiko-bot@kernel.org
To: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>,
"MPTCP Linux" <mptcp@lists.linux.dev>
Subject: Re: [PATCH mptcp-net 26/34] mptcp: don't send a FIN before the pending data on fallback
Date: Sat, 14 Nov 2026 00:27:50 +0000 [thread overview]
Message-ID: <sashiko-outbox-213924@kernel.org> (raw)
In-Reply-To: <20261113-mptcp-cmason-fixes-v1-26-9205b77e9a2f@kernel.org>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] mptcp: missing TCP FIN in mptcp_try_fallback() after data
reinjection
- [Medium] mptcp: stalled pending data and FIN after fallback in
mptcp_try_fallback()
--
commit a99710492ed63fdd9aa5e8bcc3f5436e41a0c574
Author: Matthieu Baerts (NGI0) <matttbe@kernel.org>
mptcp: don't send a FIN before the pending data on fallback
This commit updates mptcp_try_fallback() to skip shutting down the subflow
at fallback time when mptcp_send_head(sk) is non-NULL, deferring the TCP
FIN until the pending data has been pushed.
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index e61b6a3a955de..d76eaed4f01eb 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -1339,7 +1339,10 @@ static inline bool mptcp_try_fallback(struct sock *ssk, int fb_mib)
>
> if (!__mptcp_try_fallback(msk, fb_mib))
> return false;
> - if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) {
> +
> + /* no FIN before pending data: see mptcp_check_send_data_fin() */
> + if (READ_ONCE(msk->snd_data_fin_enable) && !mptcp_send_head(sk) &&
> + !(ssk->sk_shutdown & SEND_SHUTDOWN)) {
> gfp_t saved_allocation = ssk->sk_allocation;
>
> /* we are in a atomic (BH) scope, override ssk default for data
[Severity: Medium]
Can this regression skip sending a TCP FIN altogether if
__mptcp_retransmit_pending_data() has reset msk->first_pending after
mptcp_check_send_data_fin() already ran?
Once all data is pushed to the initial subflow and the socket is shut
down, mptcp_check_send_data_fin() sets msk->snd_nxt = msk->write_seq.
If an unestablished MP_JOIN subflow then closes via __mptcp_close_ssk(),
__mptcp_retransmit_pending_data() resets msk->first_pending to rtx_head
without changing msk->snd_nxt. If the initial subflow falls back to TCP
before that reinjected data is processed, !mptcp_send_head(sk) is false
and mptcp_try_fallback() skips tcp_shutdown(ssk, SEND_SHUTDOWN) even
though ssk already has all data below msk->snd_nxt in its write queue.
Later, mptcp_sendmsg_frag() skips all bytes below msk->snd_nxt and
clears msk->first_pending back to NULL, but mptcp_check_send_data_fin()
will never run again because msk->snd_nxt == msk->write_seq:
net/mptcp/protocol.c:mptcp_check_send_data_fin() {
if (!msk->snd_data_fin_enable || msk->snd_nxt + 1 != msk->write_seq ||
mptcp_send_head(sk))
return;
WRITE_ONCE(msk->snd_nxt, msk->write_seq);
...
}
As a result, the subflow never sends a TCP FIN and stays in
TCP_ESTABLISHED while the MPTCP socket remains stuck in TCP_FIN_WAIT2.
Allowing the shutdown when mptcp_data_fin_enabled(msk) is true (i.e.
!mptcp_send_head(sk) || mptcp_data_fin_enabled(msk)) would avoid this.
[Severity: Medium]
Can this regression also leave both the pending data and the TCP FIN
unsent when a non-TFO subflow falls back while both sent unacknowledged
data and unsent queued data exist?
Suppose mptcp_rtx_head(sk) has dfrag->already_sent > 0, unsent data
remains queued at mptcp_send_head(sk), and the application calls
shutdown(SHUT_WR). When the peer sends a TCP ACK without MPTCP options
that acks the in-flight TCP data on ssk, check_fully_established() (when
!tcp_sk(ssk)->syn_fastopen_child) or subflow_check_data_avail() calls
mptcp_try_fallback() without updating msk->snd_una or calling
__mptcp_check_push(sk, ssk):
net/mptcp/options.c:check_fully_established() {
...
if (!mptcp_try_fallback(ssk, MPTCP_MIB_MPCAPABLEACTFALLBACK))
goto Inevitable;
if (tcp_sk(ssk)->syn_fastopen_child) {
mptcp_data_lock(sk);
__mptcp_check_push(sk, ssk);
mptcp_data_unlock(sk);
}
return false;
...
}
mptcp_try_fallback() clears MPTCP_RTX_ENABLED and skips
tcp_shutdown(ssk, SEND_SHUTDOWN) because mptcp_send_head(sk) is
non-NULL. When the MPTCP retransmit timer later fires, msk->snd_una is
still below msk->snd_nxt, so __mptcp_retrans() sees
dfrag->already_sent > 0 after fallback, gets -1 from
__mptcp_push_retrans(), and jumps to clear_scheduled without calling
mptcp_check_and_set_pending(sk). With ssk's TCP write queue empty and
the peer waiting for the remaining data and FIN, nothing ever pushes
mptcp_send_head(sk) or sends the FIN, stalling the connection.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-mptcp-cmason-fixes-v1-0-9205b77e9a2f@kernel.org?part=26
next prev parent reply other threads:[~2026-11-14 0:27 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 19:53 [PATCH mptcp-net 00/34] mptcp: misc fixes Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 01/34] tcp: drain the queues of a listen() that fails Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 02/34] mptcp: " Matthieu Baerts (NGI0)
2026-11-13 20:13 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 03/34] mptcp: clear inet_opt in the child of an IPv6 listener Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 04/34] mptcp: pm: work on a copy of the received RM_ADDR list Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 05/34] mptcp: pm: don't drop an RM_ADDR behind a pending one Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 06/34] mptcp: pm: don't drop an RM_ADDR because of an ADD_ADDR Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 07/34] mptcp: arm the rtx timer if a push leaves data behind Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 08/34] mptcp: force the charge for the first skb of a subflow Matthieu Baerts (NGI0)
2026-11-13 20:09 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 09/34] mptcp: leave an orphan's DATA_FIN to the worker Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 10/34] mptcp: don't leak an orphan when the PM closes its last subflow Matthieu Baerts (NGI0)
2026-11-13 21:10 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 11/34] mptcp: do not use a raised snd_wnd for the send window Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 12/34] mptcp: drop non-MP_JOIN cookie ACKs on PM listeners Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 13/34] net: add __sk_net_refcnt_upgrade() with a GFP mask Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 14/34] mptcp: pm: don't let listeners pin their netns Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 15/34] mptcp: close a subflow reset for a bad mapping Matthieu Baerts (NGI0)
2026-11-13 21:40 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 16/34] mptcp: initialize drop_req in subflow_init_req() Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 17/34] mptcp: pm: kernel: count endpoint listeners as sockets in use Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 18/34] mptcp: count a listener once when listen() is called again Matthieu Baerts (NGI0)
2026-11-13 19:53 ` [PATCH mptcp-net 19/34] mptcp: do not fallback while old data is in flight Matthieu Baerts (NGI0)
2026-11-13 22:29 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 20/34] mptcp: stop resending data to a peer that fell back Matthieu Baerts (NGI0)
2026-11-13 22:53 ` sashiko-bot
2026-11-13 19:53 ` [PATCH mptcp-net 21/34] mptcp: pm: kernel: don't count signal+subflow ID 0 endp Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 22/34] selftests: mptcp: join: check re-adding " Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 23/34] mptcp: use sk instead of casting msk in check_fully_established() Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 24/34] mptcp: push queued data on passive TFO subflows becoming established Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 25/34] mptcp: push queued data on passive TFO subflows falling back to TCP Matthieu Baerts (NGI0)
2026-11-13 23:54 ` sashiko-bot
2026-11-13 19:54 ` [PATCH mptcp-net 26/34] mptcp: don't send a FIN before the pending data on fallback Matthieu Baerts (NGI0)
2026-11-14 0:27 ` sashiko-bot [this message]
2026-11-13 19:54 ` [PATCH mptcp-net 27/34] tcp: do not pass a BPF reqsk to an MPTCP listener Matthieu Baerts (NGI0)
2026-11-14 0:43 ` sashiko-bot
2026-11-13 19:54 ` [PATCH mptcp-net 28/34] mptcp: reclaim forward memory after coalescing skbs Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 29/34] mptcp: don't charge a shared page twice at accept() Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 30/34] mptcp: don't charge the backlog " Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 31/34] mptcp: don't charge a subflow twice when it joins during accept() Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 32/34] mptcp: fix dummy mapping of overlapping segments Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH mptcp-net 33/34] mptcp: continue the last mapping after a fallback Matthieu Baerts (NGI0)
2026-11-13 19:54 ` [PATCH RFC mptcp-next mptcp-net 34/34] mptcp: reset when the DSS disappears after a DATA_ACK Matthieu Baerts (NGI0)
2026-11-13 21:58 ` [PATCH mptcp-net 00/34] mptcp: misc fixes MPTCP CI
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-213924@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=matttbe@kernel.org \
--cc=mptcp@lists.linux.dev \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox