Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: Sasha Levin <sashal@kernel.org>
Subject: Re: [PATCH 6.1.y 1/3] mptcp: make fallback action and fallback decision atomic
Date: Tue, 29 Jul 2025 15:37:37 -0400	[thread overview]
Message-ID: <1753816507-dc78ebea@stable.kernel.org> (raw)
In-Reply-To: <20250728132919.3904847-6-matttbe@kernel.org>

[ Sasha's backport helper bot ]

Hi,

✅ All tests passed successfully. No issues detected.
No action required from the submitter.

The upstream commit SHA1 provided is correct: f8a1d9b18c5efc76784f5a326e905f641f839894

WARNING: Author mismatch between patch and upstream commit:
Backport author: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Commit author: Paolo Abeni <pabeni@redhat.com>

Status in newer kernel trees:
6.15.y | Not found
6.12.y | Not found
6.6.y | Not found

Note: The patch differs from the upstream commit:
---
1:  f8a1d9b18c5e ! 1:  7a5c4c08bc0b mptcp: make fallback action and fallback decision atomic
    @@ Metadata
      ## Commit message ##
         mptcp: make fallback action and fallback decision atomic
     
    +    commit f8a1d9b18c5efc76784f5a326e905f641f839894 upstream.
    +
         Syzkaller reported the following splat:
     
           WARNING: CPU: 1 PID: 7704 at net/mptcp/protocol.h:1223 __mptcp_do_fallback net/mptcp/protocol.h:1223 [inline]
    @@ Commit message
         Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
         Link: https://patch.msgid.link/20250714-net-mptcp-fallback-races-v1-1-391aff963322@kernel.org
         Signed-off-by: Jakub Kicinski <kuba@kernel.org>
    +    [ Conflicts in protocol.h, because commit 6ebf6f90ab4a ("mptcp: add
    +      mptcpi_subflows_total counter") is not in this version, and this
    +      causes conflicts in the context. Commit 65b02260a0e0 ("mptcp: export
    +      mptcp_subflow_early_fallback()") is also not in this version, and
    +      moves code from protocol.c to protocol.h, but the modification can
    +      still apply there. Conflicts in protocol.c because commit ee2708aedad0
    +      ("mptcp: use get_retrans wrapper") is not in this version and refactor
    +      the code in __mptcp_retrans(), but the modification can still be
    +      applied, just not at the same indentation level. There were other
    +      conflicts in the context due to commit 8005184fd1ca ("mptcp: refactor
    +      sndbuf auto-tuning"), commit b3ea6b272d79 ("mptcp: consolidate initial
    +      ack seq generation"), and commit 013e3179dbd2 ("mptcp: fix rcv space
    +      initialization") that are not in this version. ]
    +    Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
     
      ## net/mptcp/options.c ##
     @@ net/mptcp/options.c: static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
    @@ net/mptcp/protocol.c: static bool __mptcp_finish_join(struct mptcp_sock *msk, st
      	 * at close time
      	 */
     @@ net/mptcp/protocol.c: static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
    + 		mptcp_sock_graft(ssk, sk->sk_socket);
      
    - 	mptcp_subflow_ctx(ssk)->subflow_id = msk->subflow_id++;
      	mptcp_sockopt_sync_locked(msk, ssk);
     -	mptcp_subflow_joined(msk, ssk);
      	mptcp_stop_tout_timer(sk);
    - 	__mptcp_propagate_sndbuf(sk, ssk);
      	return true;
    + }
     @@ net/mptcp/protocol.c: static void mptcp_update_infinite_map(struct mptcp_sock *msk,
      	mpext->infinite_map = 1;
      	mpext->data_len = 0;
    @@ net/mptcp/protocol.c: static void mptcp_check_fastclose(struct mptcp_sock *msk)
      {
     +	struct mptcp_sendmsg_info info = { .data_lock_held = true, };
      	struct mptcp_sock *msk = mptcp_sk(sk);
    - 	struct mptcp_subflow_context *subflow;
     -	struct mptcp_sendmsg_info info = {};
      	struct mptcp_data_frag *dfrag;
    + 	size_t copied = 0;
      	struct sock *ssk;
    - 	int ret, err;
     @@ net/mptcp/protocol.c: static void __mptcp_retrans(struct sock *sk)
    - 			info.sent = 0;
    - 			info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len :
    - 								    dfrag->already_sent;
    + 	/* limit retransmission to the bytes already sent on some subflows */
    + 	info.sent = 0;
    + 	info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len : dfrag->already_sent;
     +
    -+			/*
    -+			 * make the whole retrans decision, xmit, disallow
    -+			 * fallback atomic
    -+			 */
    -+			spin_lock_bh(&msk->fallback_lock);
    -+			if (__mptcp_check_fallback(msk)) {
    -+				spin_unlock_bh(&msk->fallback_lock);
    -+				release_sock(ssk);
    -+				return;
    -+			}
    ++	/* make the whole retrans decision, xmit, disallow fallback atomic */
    ++	spin_lock_bh(&msk->fallback_lock);
    ++	if (__mptcp_check_fallback(msk)) {
    ++		spin_unlock_bh(&msk->fallback_lock);
    ++		release_sock(ssk);
    ++		return;
    ++	}
     +
    - 			while (info.sent < info.limit) {
    - 				ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
    - 				if (ret <= 0)
    + 	while (info.sent < info.limit) {
    + 		ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
    + 		if (ret <= 0)
     @@ net/mptcp/protocol.c: static void __mptcp_retrans(struct sock *sk)
    - 					 info.size_goal);
    - 				WRITE_ONCE(msk->allow_infinite_fallback, false);
    - 			}
    -+			spin_unlock_bh(&msk->fallback_lock);
    + 			 info.size_goal);
    + 		WRITE_ONCE(msk->allow_infinite_fallback, false);
    + 	}
    ++	spin_unlock_bh(&msk->fallback_lock);
      
    - 			release_sock(ssk);
    - 		}
    -@@ net/mptcp/protocol.c: static void __mptcp_init_sock(struct sock *sk)
    - 	msk->last_ack_recv = tcp_jiffies32;
    + 	release_sock(ssk);
    + 
    +@@ net/mptcp/protocol.c: static int __mptcp_init_sock(struct sock *sk)
    + 	msk->recovery = false;
      
      	mptcp_pm_data_init(msk);
     +	spin_lock_init(&msk->fallback_lock);
    @@ net/mptcp/protocol.c: bool mptcp_finish_join(struct sock *ssk)
     +		}
      		mptcp_subflow_joined(msk, ssk);
     +		spin_unlock_bh(&msk->fallback_lock);
    - 		mptcp_propagate_sndbuf(parent, ssk);
      		return true;
      	}
    + 
    +@@ net/mptcp/protocol.c: static void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
    + 					 struct mptcp_subflow_context *subflow)
    + {
    + 	subflow->request_mptcp = 0;
    +-	__mptcp_do_fallback(msk);
    ++	WARN_ON_ONCE(!__mptcp_try_fallback(msk));
    + }
    + 
    + static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
     
      ## net/mptcp/protocol.h ##
     @@ net/mptcp/protocol.h: struct mptcp_sock {
    - 	u32		subflow_id;
    - 	u32		setsockopt_seq;
    + 
    + 	u32 setsockopt_seq;
      	char		ca_name[TCP_CA_NAME_MAX];
     +
     +	spinlock_t	fallback_lock;	/* protects fallback and
    @@ net/mptcp/protocol.h: static inline bool mptcp_check_fallback(const struct sock
     -static inline void __mptcp_do_fallback(struct mptcp_sock *msk)
     +static inline bool __mptcp_try_fallback(struct mptcp_sock *msk)
      {
    - 	if (__mptcp_check_fallback(msk)) {
    + 	if (test_bit(MPTCP_FALLBACK_DONE, &msk->flags)) {
      		pr_debug("TCP fallback already done (msk=%p)\n", msk);
     -		return;
     +		return true;
    @@ net/mptcp/protocol.h: static inline bool mptcp_check_fallback(const struct sock
     +	return true;
      }
      
    - static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
    -@@ net/mptcp/protocol.h: static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
    - 			TCPF_SYN_RECV | TCPF_LISTEN));
    - }
    - 
     -static inline void mptcp_do_fallback(struct sock *ssk)
     +static inline bool mptcp_try_fallback(struct sock *ssk)
      {
    @@ net/mptcp/protocol.h: static inline void mptcp_do_fallback(struct sock *ssk)
      }
      
      #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)\n", __func__, a)
    -@@ net/mptcp/protocol.h: static inline void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
    - {
    - 	pr_fallback(msk);
    - 	subflow->request_mptcp = 0;
    --	__mptcp_do_fallback(msk);
    -+	WARN_ON_ONCE(!__mptcp_try_fallback(msk));
    - }
    - 
    - static inline bool mptcp_check_infinite_map(struct sk_buff *skb)
     
      ## net/mptcp/subflow.c ##
     @@ net/mptcp/subflow.c: static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
    @@ net/mptcp/subflow.c: static void subflow_finish_connect(struct sock *sk, const s
      			MPTCP_INC_STATS(sock_net(sk),
      					MPTCP_MIB_MPCAPABLEACTIVEFALLBACK);
     -			mptcp_do_fallback(sk);
    - 			pr_fallback(msk);
    + 			pr_fallback(mptcp_sk(subflow->conn));
      			goto fallback;
      		}
     @@ net/mptcp/subflow.c: static bool subflow_check_data_avail(struct sock *ssk)
    @@ net/mptcp/subflow.c: static bool subflow_check_data_avail(struct sock *ssk)
      			 * subflow_error_report() will introduce the appropriate barriers
      			 */
     @@ net/mptcp/subflow.c: static bool subflow_check_data_avail(struct sock *ssk)
    - 			WRITE_ONCE(subflow->data_avail, false);
    + 			WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
      			return false;
      		}
     -
    @@ net/mptcp/subflow.c: static bool subflow_check_data_avail(struct sock *ssk)
      	}
      
      	skb = skb_peek(&ssk->sk_receive_queue);
    -@@ net/mptcp/subflow.c: int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_pm_local *local,
    +@@ net/mptcp/subflow.c: int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
      	/* discard the subflow socket */
      	mptcp_sock_graft(ssk, sk->sk_socket);
      	iput(SOCK_INODE(sf));
    @@ net/mptcp/subflow.c: int __mptcp_subflow_connect(struct sock *sk, const struct m
      	return 0;
      
     @@ net/mptcp/subflow.c: static void subflow_state_change(struct sock *sk)
    - 
      	msk = mptcp_sk(parent);
      	if (subflow_simultaneous_connect(sk)) {
    + 		mptcp_propagate_sndbuf(parent, sk);
     -		mptcp_do_fallback(sk);
     +		WARN_ON_ONCE(!mptcp_try_fallback(sk));
    + 		mptcp_rcv_space_init(msk, sk);
      		pr_fallback(msk);
      		subflow->conn_finished = 1;
    - 		mptcp_propagate_state(parent, sk, subflow, NULL);

---

Results of testing on various branches:

| Branch                    | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| 6.1                       | Success     | Success    |

  reply	other threads:[~2025-07-29 19:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-28 13:29 [PATCH 6.1.y 0/3] mptcp: fix recent failed backports (20250721) Matthieu Baerts (NGI0)
2025-07-28 13:29 ` [PATCH 6.1.y 1/3] mptcp: make fallback action and fallback decision atomic Matthieu Baerts (NGI0)
2025-07-29 19:37   ` Sasha Levin [this message]
2025-07-28 13:29 ` [PATCH 6.1.y 2/3] mptcp: plug races between subflow fail and subflow creation Matthieu Baerts (NGI0)
2025-07-29 19:45   ` Sasha Levin
2025-07-28 13:29 ` [PATCH 6.1.y 3/3] mptcp: reset fallback status gracefully at disconnect() time Matthieu Baerts (NGI0)
2025-07-29 21:03   ` Sasha Levin

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=1753816507-dc78ebea@stable.kernel.org \
    --to=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    /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