Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mptcp: handle first subflow closing consistently

Currently, as soon as the PM closes a subflow, the msk stops accepting
data from it, even if the TCP socket could be still formally open in the
incoming direction, with the notable exception of the first subflow.

The root cause of such behavior is that code currently piggy back two
separate semantic on the subflow->disposable bit: the subflow context
must be released and that the subflow must stop accepting incoming
data.

The first subflow is never disposed, so it also never stop accepting
incoming data. Use a separate bit to mark the latter status and set such
bit in __mptcp_close_ssk() for all subflows.

Beyond making per subflow behaviour more consistent this will also
simplify the next patch.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20251121-net-next-mptcp-memcg-backlog-imp-v1-11-1f34b6c1e0b1@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Paolo Abeni and committed by
Jakub Kicinski
0eeb372d 38a4a469

+11 -6
+9 -5
net/mptcp/protocol.c
··· 851 851 struct mptcp_sock *msk = mptcp_sk(sk); 852 852 853 853 /* The peer can send data while we are shutting down this 854 - * subflow at msk destruction time, but we must avoid enqueuing 854 + * subflow at subflow destruction time, but we must avoid enqueuing 855 855 * more data to the msk receive queue 856 856 */ 857 - if (unlikely(subflow->disposable)) 857 + if (unlikely(subflow->closing)) 858 858 return; 859 859 860 860 mptcp_data_lock(sk); ··· 2437 2437 struct mptcp_sock *msk = mptcp_sk(sk); 2438 2438 bool dispose_it, need_push = false; 2439 2439 2440 + /* Do not pass RX data to the msk, even if the subflow socket is not 2441 + * going to be freed (i.e. even for the first subflow on graceful 2442 + * subflow close. 2443 + */ 2444 + lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); 2445 + subflow->closing = 1; 2446 + 2440 2447 /* If the first subflow moved to a close state before accept, e.g. due 2441 2448 * to an incoming reset or listener shutdown, the subflow socket is 2442 2449 * already deleted by inet_child_forget() and the mptcp socket can't ··· 2454 2447 /* ensure later check in mptcp_worker() will dispose the msk */ 2455 2448 sock_set_flag(sk, SOCK_DEAD); 2456 2449 mptcp_set_close_tout(sk, tcp_jiffies32 - (mptcp_close_timeout(sk) + 1)); 2457 - lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); 2458 2450 mptcp_subflow_drop_ctx(ssk); 2459 2451 goto out_release; 2460 2452 } ··· 2461 2455 dispose_it = msk->free_first || ssk != msk->first; 2462 2456 if (dispose_it) 2463 2457 list_del(&subflow->node); 2464 - 2465 - lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); 2466 2458 2467 2459 if (subflow->send_fastclose && ssk->sk_state != TCP_CLOSE) 2468 2460 tcp_set_state(ssk, TCP_CLOSE);
+2 -1
net/mptcp/protocol.h
··· 536 536 send_infinite_map : 1, 537 537 remote_key_valid : 1, /* received the peer key from */ 538 538 disposable : 1, /* ctx can be free at ulp release time */ 539 + closing : 1, /* must not pass rx data to msk anymore */ 539 540 stale : 1, /* unable to snd/rcv data, do not use for xmit */ 540 541 valid_csum_seen : 1, /* at least one csum validated */ 541 542 is_mptfo : 1, /* subflow is doing TFO */ 542 543 close_event_done : 1, /* has done the post-closed part */ 543 544 mpc_drop : 1, /* the MPC option has been dropped in a rtx */ 544 - __unused : 9; 545 + __unused : 8; 545 546 bool data_avail; 546 547 bool scheduled; 547 548 bool pm_listener; /* a listener managed by the kernel PM? */