Skip to content

Commit

Permalink
mptcp: process pending subflow error on close
Browse files Browse the repository at this point in the history
[ Upstream commit 9f1a988 ]

On incoming TCP reset, subflow closing could happen before error
propagation. That in turn could cause the socket error being ignored,
and a missing socket state transition, as reported by Daire-Byrne.

Address the issues explicitly checking for subflow socket error at
close time. To avoid code duplication, factor-out of __mptcp_error_report()
a new helper implementing the relevant bits.

Closes: multipath-tcp/mptcp_net-next#429
Fixes: 15cc104 ("mptcp: deliver ssk errors to msk")
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Paolo Abeni authored and gregkh committed Oct 10, 2023
1 parent fc8917b commit 0786516
Showing 1 changed file with 34 additions and 29 deletions.
63 changes: 34 additions & 29 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,40 +765,44 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk)
return moved;
}

void __mptcp_error_report(struct sock *sk)
static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);
int err = sock_error(ssk);
int ssk_state;

mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
int err = sock_error(ssk);
int ssk_state;
if (!err)
return false;

if (!err)
continue;
/* only propagate errors on fallen-back sockets or
* on MPC connect
*/
if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(mptcp_sk(sk)))
return false;

/* only propagate errors on fallen-back sockets or
* on MPC connect
*/
if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk))
continue;
/* We need to propagate only transition to CLOSE state.
* Orphaned socket will see such state change via
* subflow_sched_work_if_closed() and that path will properly
* destroy the msk as needed.
*/
ssk_state = inet_sk_state_load(ssk);
if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
inet_sk_state_store(sk, ssk_state);
WRITE_ONCE(sk->sk_err, -err);

/* We need to propagate only transition to CLOSE state.
* Orphaned socket will see such state change via
* subflow_sched_work_if_closed() and that path will properly
* destroy the msk as needed.
*/
ssk_state = inet_sk_state_load(ssk);
if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
inet_sk_state_store(sk, ssk_state);
WRITE_ONCE(sk->sk_err, -err);

/* This barrier is coupled with smp_rmb() in mptcp_poll() */
smp_wmb();
sk_error_report(sk);
break;
}
/* This barrier is coupled with smp_rmb() in mptcp_poll() */
smp_wmb();
sk_error_report(sk);
return true;
}

void __mptcp_error_report(struct sock *sk)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);

mptcp_for_each_subflow(msk, subflow)
if (__mptcp_subflow_error_report(sk, mptcp_subflow_tcp_sock(subflow)))
break;
}

/* In most cases we will be able to lock the mptcp socket. If its already
Expand Down Expand Up @@ -2446,6 +2450,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
}

out_release:
__mptcp_subflow_error_report(sk, ssk);
release_sock(ssk);

sock_put(ssk);
Expand Down

0 comments on commit 0786516

Please sign in to comment.