Commit 9f1a9881 authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

mptcp: process pending subflow error on close

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: https://github.com/multipath-tcp/mptcp_net-next/issues/429
Fixes: 15cc1045 ("mptcp: deliver ssk errors to msk")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Reviewed-by: default avatarMat Martineau <martineau@kernel.org>
Signed-off-by: default avatarMatthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d5fbeff1
...@@ -770,40 +770,44 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) ...@@ -770,40 +770,44 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk)
return moved; 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; int err = sock_error(ssk);
struct mptcp_sock *msk = mptcp_sk(sk); int ssk_state;
mptcp_for_each_subflow(msk, subflow) { if (!err)
struct sock *ssk = mptcp_subflow_tcp_sock(subflow); return false;
int err = sock_error(ssk);
int ssk_state;
if (!err) /* only propagate errors on fallen-back sockets or
continue; * 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 /* We need to propagate only transition to CLOSE state.
* on MPC connect * Orphaned socket will see such state change via
*/ * subflow_sched_work_if_closed() and that path will properly
if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk)) * destroy the msk as needed.
continue; */
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. /* This barrier is coupled with smp_rmb() in mptcp_poll() */
* Orphaned socket will see such state change via smp_wmb();
* subflow_sched_work_if_closed() and that path will properly sk_error_report(sk);
* destroy the msk as needed. return true;
*/ }
ssk_state = inet_sk_state_load(ssk);
if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD)) void __mptcp_error_report(struct sock *sk)
inet_sk_state_store(sk, ssk_state); {
WRITE_ONCE(sk->sk_err, -err); struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);
/* This barrier is coupled with smp_rmb() in mptcp_poll() */
smp_wmb(); mptcp_for_each_subflow(msk, subflow)
sk_error_report(sk); if (__mptcp_subflow_error_report(sk, mptcp_subflow_tcp_sock(subflow)))
break; break;
}
} }
/* In most cases we will be able to lock the mptcp socket. If its already /* In most cases we will be able to lock the mptcp socket. If its already
...@@ -2428,6 +2432,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, ...@@ -2428,6 +2432,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
} }
out_release: out_release:
__mptcp_subflow_error_report(sk, ssk);
release_sock(ssk); release_sock(ssk);
sock_put(ssk); sock_put(ssk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment