From: Kuniyuki Iwashima <kuniyu@google.com>
To: Eric Dumazet <edumazet@kernel.org>,
Neal Cardwell <ncardwell@google.com>,
"David S . Miller" <davem@davemloft.net>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Yuchung Cheng <ycheng@google.com>, Wei Wang <weiwan@google.com>,
Matthieu Baerts <matttbe@kernel.org>,
Mat Martineau <martineau@kernel.org>,
Geliang Tang <geliang@kernel.org>,
Simon Horman <horms@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Kuniyuki Iwashima <kuni1840@gmail.com>,
netdev@vger.kernel.org
Subject: [PATCH v1 net 1/3] tcp: Clear DEFER_CONNECT before tcp_connect() and in tcp_abort().
Date: Sat, 7 Nov 2026 23:56:08 +0000 [thread overview]
Message-ID: <20261107235720.3129212-2-kuniyu@google.com> (raw)
In-Reply-To: <20261107235720.3129212-1-kuniyu@google.com>
When TFO is enabled, tcp_v[46]_connect() sets sk->sk_state to
TCP_SYN_SENT and puts the socket into ehash without calling
tcp_connect().
Then, tcp_fastopen_defer_connect() sets DEFER_CONNECT, and
the first write()/sendmsg() will call tcp_connect() and send
SYN with data if possible.
If tcp_abort() kills a socket before the first write()/sendmsg(),
the unhashed socket can still call it and send SYN in TCP_CLOSE.
Also, DEFER_CONNECT is cleared after __inet_stream_connect().
So, blocking write()/sendmsg() can release lock_sock() in
inet_wait_for_connect() while DEFER_CONNECT is set, and
tcp_poll() could set EPOLLOUT even after SYN is sent.
Let's clear DEFER_CONNECT in tcp_abort() and right before
tcp_connect() in tcp_sendmsg_fastopen().
Note that the last argument of __inet_stream_connect() is
changed from is_sendmsg to defer_connect as DEFER_CONNECT
is already cleared when __inet_stream_connect() is called.
This change is also needed for the next patch.
Fixes: 19f6d3f3c842 ("net/tcp-fastopen: Add new API support")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/inet_common.h | 2 +-
net/ipv4/af_inet.c | 10 ++++++----
net/ipv4/tcp.c | 9 +++++++--
net/mptcp/protocol.c | 5 +++--
4 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 3d747896be30..0f088a213c38 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -25,7 +25,7 @@ int inet_release(struct socket *sock);
int inet_stream_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
int addr_len, int flags);
int __inet_stream_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
- int addr_len, int flags, int is_sendmsg);
+ int addr_len, int flags, bool defer_connect);
int inet_dgram_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
int addr_len, int flags);
int inet_accept(struct socket *sock, struct socket *newsock,
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 7677b0343abd..8822bae439f8 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -629,7 +629,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
* TCP 'magic' in here.
*/
int __inet_stream_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
- int addr_len, int flags, int is_sendmsg)
+ int addr_len, int flags, bool defer_connect)
{
struct sock *sk = sock->sk;
int err;
@@ -664,8 +664,10 @@ int __inet_stream_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
err = -EISCONN;
goto out;
case SS_CONNECTING:
- if (inet_test_bit(DEFER_CONNECT, sk))
- err = is_sendmsg ? -EINPROGRESS : -EISCONN;
+ if (defer_connect)
+ err = -EINPROGRESS;
+ else if (inet_test_bit(DEFER_CONNECT, sk))
+ err = -EISCONN;
else
err = -EALREADY;
/* Fall out of switch with err, set for this state */
@@ -752,7 +754,7 @@ int inet_stream_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
int err;
lock_sock(sock->sk);
- err = __inet_stream_connect(sock, uaddr, addr_len, flags, 0);
+ err = __inet_stream_connect(sock, uaddr, addr_len, flags, false);
release_sock(sock->sk);
return err;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 876f3e5f34c0..39ccbfcef136 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1057,6 +1057,7 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied,
struct tcp_sock *tp = tcp_sk(sk);
struct inet_sock *inet = inet_sk(sk);
struct sockaddr *uaddr = msg->msg_name;
+ bool defer_connect = false;
int err, flags;
if (!(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) &
@@ -1076,6 +1077,9 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied,
tp->fastopen_req->uarg = uarg;
if (inet_test_bit(DEFER_CONNECT, sk)) {
+ inet_clear_bit(DEFER_CONNECT, sk);
+ defer_connect = true;
+
err = tcp_connect(sk);
/* Same failure procedure as in tcp_v4/6_connect */
if (err) {
@@ -1086,14 +1090,13 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied,
}
flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
err = __inet_stream_connect(sk->sk_socket, (struct sockaddr_unsized *)uaddr,
- msg->msg_namelen, flags, 1);
+ msg->msg_namelen, flags, defer_connect);
/* fastopen_req could already be freed in __inet_stream_connect
* if the connection times out or gets rst
*/
if (tp->fastopen_req) {
*copied = tp->fastopen_req->copied;
tcp_free_fastopen_req(tp);
- inet_clear_bit(DEFER_CONNECT, sk);
}
return err;
}
@@ -5148,6 +5151,8 @@ int tcp_abort(struct sock *sk, int err)
/* Don't race with userspace socket closes such as tcp_close. */
lock_sock(sk);
+ inet_clear_bit(DEFER_CONNECT, sk);
+
/* Avoid closing the same socket twice. */
if (sk->sk_state == TCP_CLOSE) {
if (!has_current_bpf_ctx())
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 7a22e9388e0e..8968db58083e 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1920,10 +1920,12 @@ static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
msg->msg_flags = saved_flags;
release_sock(ssk);
+ inet_clear_bit(DEFER_CONNECT, sk);
+
/* do the blocking bits of inet_stream_connect outside the ssk socket lock */
if (ret == -EINPROGRESS && !(msg->msg_flags & MSG_DONTWAIT)) {
ret = __inet_stream_connect(sk->sk_socket, msg->msg_name,
- msg->msg_namelen, msg->msg_flags, 1);
+ msg->msg_namelen, msg->msg_flags, true);
/* Keep the same behaviour of plain TCP: zero the copied bytes in
* case of any error, except timeout or signal
@@ -1941,7 +1943,6 @@ static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
sk->sk_socket->state = SS_UNCONNECTED;
}
}
- inet_clear_bit(DEFER_CONNECT, sk);
return ret;
}
--
2.56.0.455.g6c5a503b38-goog
next prev parent reply other threads:[~2026-11-07 23:57 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 23:56 [PATCH v1 net 0/3] tcp: Small fixes for DEFER_CONNECT Kuniyuki Iwashima
2026-11-07 23:56 ` Kuniyuki Iwashima [this message]
2026-11-10 18:46 ` [PATCH v1 net 1/3] tcp: Clear DEFER_CONNECT before tcp_connect() and in tcp_abort() Matthieu Baerts
2026-11-10 19:12 ` Kuniyuki Iwashima
2026-11-10 19:14 ` Matthieu Baerts
2026-11-07 23:56 ` [PATCH v1 net 2/3] tcp: Drop any segments if DEFER_CONNECT is set Kuniyuki Iwashima
2026-11-07 23:56 ` [PATCH v1 net 3/3] selftest: packetdrill: Add test for DEFER_CONNECT Kuniyuki Iwashima
2026-11-11 22:12 ` [PATCH v1 net 0/3] tcp: Small fixes " patchwork-bot+netdevbpf
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=20261107235720.3129212-2-kuniyu@google.com \
--to=kuniyu@google.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=geliang@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=kuni1840@gmail.com \
--cc=martineau@kernel.org \
--cc=matttbe@kernel.org \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=weiwan@google.com \
--cc=ycheng@google.com \
/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