aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2025-01-28 05:02:22 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2025-01-28 05:02:22 +0000
commit06bf119f265c38c0ed16a1461fdc43356c3edf7a (patch)
tree42fa09ef27909e94c2181236df27b34c9a37d78f
parentaa90fbed151de512ab6e59f75df009533a15751f (diff)
sockets/tcp: quick fix for regression with SO_REUSEPORT_LB
There was a long living problem that pr_listen is called every time on consecutive listen(2) syscalls. Up until today it produces spurious TCP state change events in tracing software and other harmless problems. But with 7cbb6b6e28db we started to call LIST_REMOVE() twice on the same entry. This is quite ugly, but quick and robust fix against regression, that we decided to put in the scope of the January stabilization week. A better refactoring will happen later. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D48703 Fixes: 7cbb6b6e28db33095a1cf7a8887921a5ec969824
-rw-r--r--sys/netinet/tcp_usrreq.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 3e73e448a9f7..c6713a0bb4cb 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -355,9 +355,10 @@ out:
static int
tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
{
- int error = 0;
struct inpcb *inp;
struct tcpcb *tp;
+ int error = 0;
+ bool already_listening;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
@@ -369,6 +370,7 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
tp = intotcpcb(inp);
SOCK_LOCK(so);
+ already_listening = SOLISTENING(so);
error = solisten_proto_check(so);
if (error != 0) {
SOCK_UNLOCK(so);
@@ -390,6 +392,8 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
solisten_proto_abort(so);
}
SOCK_UNLOCK(so);
+ if (already_listening)
+ goto out;
if (error == 0)
in_pcblisten(inp);
@@ -408,10 +412,11 @@ out:
static int
tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
{
- int error = 0;
struct inpcb *inp;
struct tcpcb *tp;
u_char vflagsav;
+ int error = 0;
+ bool already_listening;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
@@ -425,6 +430,7 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
vflagsav = inp->inp_vflag;
SOCK_LOCK(so);
+ already_listening = SOLISTENING(so);
error = solisten_proto_check(so);
if (error != 0) {
SOCK_UNLOCK(so);
@@ -449,6 +455,8 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
solisten_proto_abort(so);
}
SOCK_UNLOCK(so);
+ if (already_listening)
+ goto out;
if (error == 0)
in_pcblisten(inp);