net/mptcp/protocol.c | 39 +++++++++++++++------------------------ net/mptcp/subflow.c | 17 ++++++++++------- 2 files changed, 25 insertions(+), 31 deletions(-)
From: Paolo Abeni <pabeni@redhat.com>
commit 81c1d029016001f994ce1c46849c5e9900d8eab8 upstream.
An orphaned msk releases the used resources via the worker,
when the latter first see the msk in CLOSED status.
If the msk status transitions to TCP_CLOSE in the release callback
invoked by the worker's final release_sock(), such instance of the
workqueue will not take any action.
Additionally the MPTCP code prevents scheduling the worker once the
socket reaches the CLOSE status: such msk resources will be leaked.
The only code path that can trigger the above scenario is the
__mptcp_check_send_data_fin() in fallback mode.
Address the issue removing the special handling of fallback socket
in __mptcp_check_send_data_fin(), consolidating the state machine
for fallback and non fallback socket.
Since non-fallback sockets do not send and do not receive data_fin,
the mptcp code can update the msk internal status to match the next
step in the SM every time data fin (ack) should be generated or
received.
As a consequence we can remove a bunch of checks for fallback from
the fastpath.
Fixes: 6e628cd3a8f7 ("mptcp: use mptcp release_cb for delayed tasks")
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: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
---
Conflicting with:
- 0522b424c4c2 ("mptcp: add do_check_data_fin to replace copied")
- 3e5014909b56 ("mptcp: cleanup MPJ subflow list handling")
I took the new modifications but leaving the old variable name for
"copied" instead of "do_check_data_fin" and the calls to
__mptcp_flush_join_list()
Applied on top of d2efde0d1c2e ("Linux 5.15.119-rc1").
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
---
net/mptcp/protocol.c | 39 +++++++++++++++------------------------
net/mptcp/subflow.c | 17 ++++++++++-------
2 files changed, 25 insertions(+), 31 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index f2977201f8fa..82b1583f709d 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -51,7 +51,7 @@ enum {
static struct percpu_counter mptcp_sockets_allocated;
static void __mptcp_destroy_sock(struct sock *sk);
-static void __mptcp_check_send_data_fin(struct sock *sk);
+static void mptcp_check_send_data_fin(struct sock *sk);
DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
static struct net_device mptcp_napi_dev;
@@ -355,8 +355,7 @@ static bool mptcp_pending_data_fin_ack(struct sock *sk)
{
struct mptcp_sock *msk = mptcp_sk(sk);
- return !__mptcp_check_fallback(msk) &&
- ((1 << sk->sk_state) &
+ return ((1 << sk->sk_state) &
(TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK)) &&
msk->write_seq == READ_ONCE(msk->snd_una);
}
@@ -509,9 +508,6 @@ static bool mptcp_check_data_fin(struct sock *sk)
u64 rcv_data_fin_seq;
bool ret = false;
- if (__mptcp_check_fallback(msk))
- return ret;
-
/* Need to ack a DATA_FIN received from a peer while this side
* of the connection is in ESTABLISHED, FIN_WAIT1, or FIN_WAIT2.
* msk->rcv_data_fin was set when parsing the incoming options
@@ -549,7 +545,8 @@ static bool mptcp_check_data_fin(struct sock *sk)
}
ret = true;
- mptcp_send_ack(msk);
+ if (!__mptcp_check_fallback(msk))
+ mptcp_send_ack(msk);
mptcp_close_wake_up(sk);
}
return ret;
@@ -1612,7 +1609,7 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
if (!mptcp_timer_pending(sk))
mptcp_reset_timer(sk);
if (copied)
- __mptcp_check_send_data_fin(sk);
+ mptcp_check_send_data_fin(sk);
}
static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk)
@@ -2451,7 +2448,6 @@ static void mptcp_worker(struct work_struct *work)
if (unlikely((1 << state) & (TCPF_CLOSE | TCPF_LISTEN)))
goto unlock;
- mptcp_check_data_fin_ack(sk);
mptcp_flush_join_list(msk);
mptcp_check_fastclose(msk);
@@ -2462,7 +2458,8 @@ static void mptcp_worker(struct work_struct *work)
if (test_and_clear_bit(MPTCP_WORK_EOF, &msk->flags))
mptcp_check_for_eof(msk);
- __mptcp_check_send_data_fin(sk);
+ mptcp_check_send_data_fin(sk);
+ mptcp_check_data_fin_ack(sk);
mptcp_check_data_fin(sk);
/* There is no point in keeping around an orphaned sk timedout or
@@ -2591,6 +2588,12 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
pr_debug("Fallback");
ssk->sk_shutdown |= how;
tcp_shutdown(ssk, how);
+
+ /* simulate the data_fin ack reception to let the state
+ * machine move forward
+ */
+ WRITE_ONCE(mptcp_sk(sk)->snd_una, mptcp_sk(sk)->snd_nxt);
+ mptcp_schedule_work(sk);
} else {
pr_debug("Sending DATA_FIN on subflow %p", ssk);
tcp_send_ack(ssk);
@@ -2630,7 +2633,7 @@ static int mptcp_close_state(struct sock *sk)
return next & TCP_ACTION_FIN;
}
-static void __mptcp_check_send_data_fin(struct sock *sk)
+static void mptcp_check_send_data_fin(struct sock *sk)
{
struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);
@@ -2648,18 +2651,6 @@ static void __mptcp_check_send_data_fin(struct sock *sk)
WRITE_ONCE(msk->snd_nxt, msk->write_seq);
- /* fallback socket will not get data_fin/ack, can move to the next
- * state now
- */
- if (__mptcp_check_fallback(msk)) {
- if ((1 << sk->sk_state) & (TCPF_CLOSING | TCPF_LAST_ACK)) {
- inet_sk_state_store(sk, TCP_CLOSE);
- mptcp_close_wake_up(sk);
- } else if (sk->sk_state == TCP_FIN_WAIT1) {
- inet_sk_state_store(sk, TCP_FIN_WAIT2);
- }
- }
-
mptcp_flush_join_list(msk);
mptcp_for_each_subflow(msk, subflow) {
struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
@@ -2680,7 +2671,7 @@ static void __mptcp_wr_shutdown(struct sock *sk)
WRITE_ONCE(msk->write_seq, msk->write_seq + 1);
WRITE_ONCE(msk->snd_data_fin_enable, 1);
- __mptcp_check_send_data_fin(sk);
+ mptcp_check_send_data_fin(sk);
}
static void __mptcp_destroy_sock(struct sock *sk)
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 9b89999062c9..666f6720db76 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1653,14 +1653,16 @@ static void subflow_state_change(struct sock *sk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct sock *parent = subflow->conn;
+ struct mptcp_sock *msk;
__subflow_state_change(sk);
+ msk = mptcp_sk(parent);
if (subflow_simultaneous_connect(sk)) {
mptcp_propagate_sndbuf(parent, sk);
mptcp_do_fallback(sk);
- mptcp_rcv_space_init(mptcp_sk(parent), sk);
- pr_fallback(mptcp_sk(parent));
+ mptcp_rcv_space_init(msk, sk);
+ pr_fallback(msk);
subflow->conn_finished = 1;
mptcp_set_connected(parent);
}
@@ -1676,11 +1678,12 @@ static void subflow_state_change(struct sock *sk)
subflow_sched_work_if_closed(mptcp_sk(parent), sk);
- if (__mptcp_check_fallback(mptcp_sk(parent)) &&
- !subflow->rx_eof && subflow_is_done(sk)) {
- subflow->rx_eof = 1;
- mptcp_subflow_eof(parent);
- }
+ /* when the fallback subflow closes the rx side, trigger a 'dummy'
+ * ingress data fin, so that the msk state will follow along
+ */
+ if (__mptcp_check_fallback(msk) && subflow_is_done(sk) && msk->first == sk &&
+ mptcp_update_rcv_data_fin(msk, READ_ONCE(msk->ack_seq), true))
+ mptcp_schedule_work(parent);
}
static int subflow_ulp_init(struct sock *sk)
--
2.40.1
On Tue, Jun 27, 2023 at 03:25:57PM +0200, Matthieu Baerts wrote: > From: Paolo Abeni <pabeni@redhat.com> > > commit 81c1d029016001f994ce1c46849c5e9900d8eab8 upstream. > > An orphaned msk releases the used resources via the worker, > when the latter first see the msk in CLOSED status. > > If the msk status transitions to TCP_CLOSE in the release callback > invoked by the worker's final release_sock(), such instance of the > workqueue will not take any action. > > Additionally the MPTCP code prevents scheduling the worker once the > socket reaches the CLOSE status: such msk resources will be leaked. > > The only code path that can trigger the above scenario is the > __mptcp_check_send_data_fin() in fallback mode. > > Address the issue removing the special handling of fallback socket > in __mptcp_check_send_data_fin(), consolidating the state machine > for fallback and non fallback socket. > > Since non-fallback sockets do not send and do not receive data_fin, > the mptcp code can update the msk internal status to match the next > step in the SM every time data fin (ack) should be generated or > received. > > As a consequence we can remove a bunch of checks for fallback from > the fastpath. > > Fixes: 6e628cd3a8f7 ("mptcp: use mptcp release_cb for delayed tasks") > 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: Jakub Kicinski <kuba@kernel.org> > Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> > --- > Conflicting with: > - 0522b424c4c2 ("mptcp: add do_check_data_fin to replace copied") > - 3e5014909b56 ("mptcp: cleanup MPJ subflow list handling") > > I took the new modifications but leaving the old variable name for > "copied" instead of "do_check_data_fin" and the calls to > __mptcp_flush_join_list() > > Applied on top of d2efde0d1c2e ("Linux 5.15.119-rc1"). > > Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> All backports now queued up, thanks. greg k-h
© 2016 - 2024 Red Hat, Inc.