git: 8b4d0bec4311 - main - inpcb: make in_pcbbind() acquire the hash lock internally
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 12 Apr 2026 18:35:36 UTC
The branch main has been updated by glebius:
URL: https://cgit.FreeBSD.org/src/commit/?id=8b4d0bec43116f5d4d1fba89d1b81f1d05805147
commit 8b4d0bec43116f5d4d1fba89d1b81f1d05805147
Author: Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-04-12 18:33:20 +0000
Commit: Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-04-12 18:33:20 +0000
inpcb: make in_pcbbind() acquire the hash lock internally
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D55970
---
sys/netinet/in_pcb.c | 9 +++++++--
sys/netinet/tcp_usrreq.c | 10 ----------
sys/netinet/udp_usrreq.c | 6 ------
sys/netinet6/in6_pcb.c | 15 +++++++++++----
sys/netinet6/udp6_usrreq.c | 4 ----
5 files changed, 18 insertions(+), 26 deletions(-)
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index f1053f6abe03..6c5b7869d945 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -727,22 +727,27 @@ in_pcbbind(struct inpcb *inp, struct sockaddr_in *sin, int flags,
KASSERT(sin == NULL || sin->sin_len == sizeof(struct sockaddr_in),
("%s: invalid address length for %p", __func__, sin));
INP_WLOCK_ASSERT(inp);
- INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
if (inp->inp_lport != 0 || inp->inp_laddr.s_addr != INADDR_ANY)
return (EINVAL);
anonport = sin == NULL || sin->sin_port == 0;
+
+ INP_HASH_WLOCK(inp->inp_pcbinfo);
error = in_pcbbind_setup(inp, sin, &inp->inp_laddr.s_addr,
&inp->inp_lport, flags, cred);
- if (error)
+ if (error) {
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
return (error);
+ }
if (__predict_false((error = in_pcbinshash(inp)) != 0)) {
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
MPASS(inp->inp_socket->so_options & SO_REUSEPORT_LB);
inp->inp_laddr.s_addr = INADDR_ANY;
inp->inp_lport = 0;
inp->inp_flags &= ~INP_BOUNDFIB;
return (error);
}
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
if (anonport)
inp->inp_flags |= INP_ANONPORT;
return (0);
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index ce13f1a9cefe..72100a0fb9d9 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -256,10 +256,8 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
error = EAFNOSUPPORT;
goto out;
}
- INP_HASH_WLOCK(&V_tcbinfo);
error = in_pcbbind(inp, sinp, V_tcp_bind_all_fibs ? 0 : INPBIND_FIB,
td->td_ucred);
- INP_HASH_WUNLOCK(&V_tcbinfo);
out:
tcp_bblog_pru(tp, PRU_BIND, error);
TCP_PROBE2(debug__user, tp, PRU_BIND);
@@ -305,7 +303,6 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
goto out;
}
- INP_HASH_WLOCK(&V_tcbinfo);
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
#ifdef INET
@@ -318,20 +315,17 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
in6_sin6_2_sin(&sin, sin6);
if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
error = EAFNOSUPPORT;
- INP_HASH_WUNLOCK(&V_tcbinfo);
goto out;
}
inp->inp_vflag |= INP_IPV4;
inp->inp_vflag &= ~INP_IPV6;
error = in_pcbbind(inp, &sin, 0, td->td_ucred);
- INP_HASH_WUNLOCK(&V_tcbinfo);
goto out;
}
}
#endif
error = in6_pcbbind(inp, sin6, V_tcp_bind_all_fibs ? 0 : INPBIND_FIB,
td->td_ucred);
- INP_HASH_WUNLOCK(&V_tcbinfo);
out:
if (error != 0)
inp->inp_vflag = vflagsav;
@@ -368,10 +362,8 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
goto out;
}
if (inp->inp_lport == 0) {
- INP_HASH_WLOCK(&V_tcbinfo);
error = in_pcbbind(inp, NULL,
V_tcp_bind_all_fibs ? 0 : INPBIND_FIB, td->td_ucred);
- INP_HASH_WUNLOCK(&V_tcbinfo);
}
if (error == 0) {
tcp_state_change(tp, TCPS_LISTEN);
@@ -426,7 +418,6 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
SOCK_UNLOCK(so);
goto out;
}
- INP_HASH_WLOCK(&V_tcbinfo);
if (inp->inp_lport == 0) {
inp->inp_vflag &= ~INP_IPV4;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
@@ -434,7 +425,6 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
error = in6_pcbbind(inp, NULL,
V_tcp_bind_all_fibs ? 0 : INPBIND_FIB, td->td_ucred);
}
- INP_HASH_WUNLOCK(&V_tcbinfo);
if (error == 0) {
tcp_state_change(tp, TCPS_LISTEN);
solisten_proto(so, backlog);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index e425af92048d..3e8011542753 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1356,10 +1356,8 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
.sin_len = sizeof(struct sockaddr_in),
};
- INP_HASH_WLOCK(pcbinfo);
error = in_pcbbind(inp, &wild, V_udp_bind_all_fibs ?
0 : INPBIND_FIB, td->td_ucred);
- INP_HASH_WUNLOCK(pcbinfo);
if (error)
goto release;
lport = inp->inp_lport;
@@ -1599,11 +1597,9 @@ static int
udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct inpcb *inp;
- struct inpcbinfo *pcbinfo;
struct sockaddr_in *sinp;
int error;
- pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp_bind: inp == NULL"));
@@ -1622,10 +1618,8 @@ udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return (EINVAL);
INP_WLOCK(inp);
- INP_HASH_WLOCK(pcbinfo);
error = in_pcbbind(inp, sinp, V_udp_bind_all_fibs ? 0 : INPBIND_FIB,
td->td_ucred);
- INP_HASH_WUNLOCK(pcbinfo);
INP_WUNLOCK(inp);
return (error);
}
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 09a62a53e054..c4469136fc90 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -297,7 +297,6 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, int flags,
int error, fib, lookupflags, sooptions;
INP_WLOCK_ASSERT(inp);
- INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
return (EINVAL);
@@ -310,6 +309,7 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, int flags,
if ((error = prison_local_ip6(cred, &inp->in6p_laddr,
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
return (error);
+ INP_HASH_WLOCK(inp->inp_pcbinfo);
} else {
KASSERT(sin6->sin6_family == AF_INET6,
("%s: invalid address family for %p", __func__, sin6));
@@ -326,11 +326,14 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, int flags,
fib = (flags & INPBIND_FIB) != 0 ? inp->inp_inc.inc_fibnum :
RT_ALL_FIBS;
+ INP_HASH_WLOCK(inp->inp_pcbinfo);
/* See if this address/port combo is available. */
- error = in6_pcbbind_avail(inp, sin6, fib, sooptions, lookupflags,
- cred);
- if (error != 0)
+ error = in6_pcbbind_avail(inp, sin6, fib, sooptions,
+ lookupflags, cred);
+ if (error != 0) {
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
return (error);
+ }
lport = sin6->sin6_port;
inp->in6p_laddr = sin6->sin6_addr;
@@ -339,6 +342,7 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, int flags,
inp->inp_flags |= INP_BOUNDFIB;
if (lport == 0) {
if ((error = in6_pcbsetport(&inp->in6p_laddr, inp, cred)) != 0) {
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
/* Undo an address bind that may have occurred. */
inp->inp_flags &= ~INP_BOUNDFIB;
inp->in6p_laddr = in6addr_any;
@@ -347,12 +351,15 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr_in6 *sin6, int flags,
} else {
inp->inp_lport = lport;
if (in_pcbinshash(inp) != 0) {
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
inp->inp_flags &= ~INP_BOUNDFIB;
inp->in6p_laddr = in6addr_any;
inp->inp_lport = 0;
return (EAGAIN);
}
}
+ INP_HASH_WUNLOCK(inp->inp_pcbinfo);
+
return (0);
}
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 715f43f0d47c..6e37586f16e4 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -1046,11 +1046,9 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct sockaddr_in6 *sin6_p;
struct inpcb *inp;
- struct inpcbinfo *pcbinfo;
int error;
u_char vflagsav;
- pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
@@ -1062,7 +1060,6 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
sin6_p = (struct sockaddr_in6 *)nam;
INP_WLOCK(inp);
- INP_HASH_WLOCK(pcbinfo);
vflagsav = inp->inp_vflag;
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
@@ -1091,7 +1088,6 @@ out:
#endif
if (error != 0)
inp->inp_vflag = vflagsav;
- INP_HASH_WUNLOCK(pcbinfo);
INP_WUNLOCK(inp);
return (error);
}