inpcb: make in_pcbconnect() acquire the hash lock internally
Reviewed by: pouria, rrs, markj Differential Revision: https://reviews.freebsd.org/D55971
This commit is contained in:
+12
-5
@@ -1096,8 +1096,8 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
|
|||||||
int error;
|
int error;
|
||||||
bool anonport;
|
bool anonport;
|
||||||
|
|
||||||
|
NET_EPOCH_ASSERT();
|
||||||
INP_WLOCK_ASSERT(inp);
|
INP_WLOCK_ASSERT(inp);
|
||||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
|
||||||
KASSERT(in_nullhost(inp->inp_faddr),
|
KASSERT(in_nullhost(inp->inp_faddr),
|
||||||
("%s: inp is already connected", __func__));
|
("%s: inp is already connected", __func__));
|
||||||
KASSERT(sin->sin_family == AF_INET,
|
KASSERT(sin->sin_family == AF_INET,
|
||||||
@@ -1134,10 +1134,13 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
|
|||||||
} else
|
} else
|
||||||
faddr = sin->sin_addr;
|
faddr = sin->sin_addr;
|
||||||
|
|
||||||
|
INP_HASH_WLOCK(inp->inp_pcbinfo);
|
||||||
if (in_nullhost(inp->inp_laddr)) {
|
if (in_nullhost(inp->inp_laddr)) {
|
||||||
error = in_pcbladdr(inp, &faddr, &laddr, cred);
|
error = in_pcbladdr(inp, &faddr, &laddr, cred);
|
||||||
if (error)
|
if (__predict_false(error)) {
|
||||||
|
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||||
return (error);
|
return (error);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
laddr = inp->inp_laddr;
|
laddr = inp->inp_laddr;
|
||||||
|
|
||||||
@@ -1154,13 +1157,16 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
|
|||||||
error = in_pcb_lport_dest(inp, (struct sockaddr *)&lsin,
|
error = in_pcb_lport_dest(inp, (struct sockaddr *)&lsin,
|
||||||
&lport, (struct sockaddr *)&fsin, sin->sin_port, cred,
|
&lport, (struct sockaddr *)&fsin, sin->sin_port, cred,
|
||||||
INPLOOKUP_WILDCARD);
|
INPLOOKUP_WILDCARD);
|
||||||
if (error)
|
if (__predict_false(error)) {
|
||||||
|
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||||
return (error);
|
return (error);
|
||||||
|
}
|
||||||
} else if (in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr,
|
} else if (in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr,
|
||||||
sin->sin_port, laddr, inp->inp_lport, 0, M_NODOM, RT_ALL_FIBS) !=
|
sin->sin_port, laddr, inp->inp_lport, 0, M_NODOM, RT_ALL_FIBS) !=
|
||||||
NULL)
|
NULL) {
|
||||||
|
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||||
return (EADDRINUSE);
|
return (EADDRINUSE);
|
||||||
else
|
} else
|
||||||
lport = inp->inp_lport;
|
lport = inp->inp_lport;
|
||||||
|
|
||||||
MPASS(!in_nullhost(inp->inp_laddr) || inp->inp_lport != 0 ||
|
MPASS(!in_nullhost(inp->inp_laddr) || inp->inp_lport != 0 ||
|
||||||
@@ -1176,6 +1182,7 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
|
|||||||
MPASS(error == 0);
|
MPASS(error == 0);
|
||||||
} else
|
} else
|
||||||
in_pcbrehash(inp);
|
in_pcbrehash(inp);
|
||||||
|
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||||
|
|
||||||
if (V_fib_hash_outbound) {
|
if (V_fib_hash_outbound) {
|
||||||
uint32_t hash_val, hash_type;
|
uint32_t hash_val, hash_type;
|
||||||
|
|||||||
@@ -846,9 +846,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
|||||||
sin6.sin6_addr = sc->sc_inc.inc6_faddr;
|
sin6.sin6_addr = sc->sc_inc.inc6_faddr;
|
||||||
sin6.sin6_port = sc->sc_inc.inc_fport;
|
sin6.sin6_port = sc->sc_inc.inc_fport;
|
||||||
sin6.sin6_flowinfo = sin6.sin6_scope_id = 0;
|
sin6.sin6_flowinfo = sin6.sin6_scope_id = 0;
|
||||||
INP_HASH_WLOCK(&V_tcbinfo);
|
|
||||||
error = in6_pcbconnect(inp, &sin6, thread0.td_ucred, false);
|
error = in6_pcbconnect(inp, &sin6, thread0.td_ucred, false);
|
||||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto abort;
|
goto abort;
|
||||||
/* Override flowlabel from in6_pcbconnect. */
|
/* Override flowlabel from in6_pcbconnect. */
|
||||||
@@ -875,9 +873,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
|
|||||||
sin.sin_addr = sc->sc_inc.inc_faddr;
|
sin.sin_addr = sc->sc_inc.inc_faddr;
|
||||||
sin.sin_port = sc->sc_inc.inc_fport;
|
sin.sin_port = sc->sc_inc.inc_fport;
|
||||||
bzero((caddr_t)sin.sin_zero, sizeof(sin.sin_zero));
|
bzero((caddr_t)sin.sin_zero, sizeof(sin.sin_zero));
|
||||||
INP_HASH_WLOCK(&V_tcbinfo);
|
|
||||||
error = in_pcbconnect(inp, &sin, thread0.td_ucred);
|
error = in_pcbconnect(inp, &sin, thread0.td_ucred);
|
||||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1424,9 +1424,7 @@ tcp_connect(struct tcpcb *tp, struct sockaddr_in *sin, struct thread *td)
|
|||||||
if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0))
|
if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0))
|
||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
|
|
||||||
INP_HASH_WLOCK(&V_tcbinfo);
|
|
||||||
error = in_pcbconnect(inp, sin, td->td_ucred);
|
error = in_pcbconnect(inp, sin, td->td_ucred);
|
||||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
@@ -1473,9 +1471,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr_in6 *sin6, struct thread *td)
|
|||||||
if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0))
|
if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0))
|
||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
|
|
||||||
INP_HASH_WLOCK(&V_tcbinfo);
|
|
||||||
error = in6_pcbconnect(inp, sin6, td->td_ucred, true);
|
error = in6_pcbconnect(inp, sin6, td->td_ucred, true);
|
||||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
|
|||||||
@@ -1644,11 +1644,9 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
struct inpcbinfo *pcbinfo;
|
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
|
|
||||||
inp = sotoinpcb(so);
|
inp = sotoinpcb(so);
|
||||||
KASSERT(inp != NULL, ("udp_connect: inp == NULL"));
|
KASSERT(inp != NULL, ("udp_connect: inp == NULL"));
|
||||||
|
|
||||||
@@ -1669,9 +1667,7 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
INP_HASH_WLOCK(pcbinfo);
|
|
||||||
error = in_pcbconnect(inp, sin, td->td_ucred);
|
error = in_pcbconnect(inp, sin, td->td_ucred);
|
||||||
INP_HASH_WUNLOCK(pcbinfo);
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
soisconnected(so);
|
soisconnected(so);
|
||||||
|
|||||||
+11
-4
@@ -444,7 +444,6 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
|
|||||||
|
|
||||||
NET_EPOCH_ASSERT();
|
NET_EPOCH_ASSERT();
|
||||||
INP_WLOCK_ASSERT(inp);
|
INP_WLOCK_ASSERT(inp);
|
||||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
|
||||||
KASSERT(sin6->sin6_family == AF_INET6,
|
KASSERT(sin6->sin6_family == AF_INET6,
|
||||||
("%s: invalid address family for %p", __func__, sin6));
|
("%s: invalid address family for %p", __func__, sin6));
|
||||||
KASSERT(sin6->sin6_len == sizeof(*sin6),
|
KASSERT(sin6->sin6_len == sizeof(*sin6),
|
||||||
@@ -468,24 +467,31 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
|
|||||||
* Call inner routine, to assign local interface address.
|
* Call inner routine, to assign local interface address.
|
||||||
* in6_pcbladdr() may automatically fill in sin6_scope_id.
|
* in6_pcbladdr() may automatically fill in sin6_scope_id.
|
||||||
*/
|
*/
|
||||||
|
INP_HASH_WLOCK(pcbinfo);
|
||||||
if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr,
|
if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr,
|
||||||
sas_required)) != 0)
|
sas_required)) != 0) {
|
||||||
|
INP_HASH_WUNLOCK(pcbinfo);
|
||||||
return (error);
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr,
|
if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr,
|
||||||
sin6->sin6_port, IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ?
|
sin6->sin6_port, IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ?
|
||||||
&laddr6.sin6_addr : &inp->in6p_laddr, inp->inp_lport, 0,
|
&laddr6.sin6_addr : &inp->in6p_laddr, inp->inp_lport, 0,
|
||||||
M_NODOM, RT_ALL_FIBS) != NULL)
|
M_NODOM, RT_ALL_FIBS) != NULL) {
|
||||||
|
INP_HASH_WUNLOCK(pcbinfo);
|
||||||
return (EADDRINUSE);
|
return (EADDRINUSE);
|
||||||
|
}
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
|
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
|
||||||
if (inp->inp_lport == 0) {
|
if (inp->inp_lport == 0) {
|
||||||
error = in_pcb_lport_dest(inp,
|
error = in_pcb_lport_dest(inp,
|
||||||
(struct sockaddr *) &laddr6, &inp->inp_lport,
|
(struct sockaddr *) &laddr6, &inp->inp_lport,
|
||||||
(struct sockaddr *) sin6, sin6->sin6_port, cred,
|
(struct sockaddr *) sin6, sin6->sin6_port, cred,
|
||||||
INPLOOKUP_WILDCARD);
|
INPLOOKUP_WILDCARD);
|
||||||
if (error)
|
if (__predict_false(error)) {
|
||||||
|
INP_HASH_WUNLOCK(pcbinfo);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
inp->in6p_laddr = laddr6.sin6_addr;
|
inp->in6p_laddr = laddr6.sin6_addr;
|
||||||
}
|
}
|
||||||
inp->in6p_faddr = sin6->sin6_addr;
|
inp->in6p_faddr = sin6->sin6_addr;
|
||||||
@@ -501,6 +507,7 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
|
|||||||
MPASS(error == 0);
|
MPASS(error == 0);
|
||||||
} else
|
} else
|
||||||
in_pcbrehash(inp);
|
in_pcbrehash(inp);
|
||||||
|
INP_HASH_WUNLOCK(pcbinfo);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1120,12 +1120,10 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
struct inpcbinfo *pcbinfo;
|
|
||||||
struct sockaddr_in6 *sin6;
|
struct sockaddr_in6 *sin6;
|
||||||
int error;
|
int error;
|
||||||
u_char vflagsav;
|
u_char vflagsav;
|
||||||
|
|
||||||
pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
|
|
||||||
inp = sotoinpcb(so);
|
inp = sotoinpcb(so);
|
||||||
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
|
KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
|
||||||
|
|
||||||
@@ -1163,9 +1161,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
inp->inp_vflag |= INP_IPV4;
|
inp->inp_vflag |= INP_IPV4;
|
||||||
inp->inp_vflag &= ~INP_IPV6;
|
inp->inp_vflag &= ~INP_IPV6;
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
INP_HASH_WLOCK(pcbinfo);
|
|
||||||
error = in_pcbconnect(inp, &sin, td->td_ucred);
|
error = in_pcbconnect(inp, &sin, td->td_ucred);
|
||||||
INP_HASH_WUNLOCK(pcbinfo);
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
/*
|
/*
|
||||||
* If connect succeeds, mark socket as connected. If
|
* If connect succeeds, mark socket as connected. If
|
||||||
@@ -1196,9 +1192,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
inp->inp_vflag &= ~INP_IPV4;
|
inp->inp_vflag &= ~INP_IPV4;
|
||||||
inp->inp_vflag |= INP_IPV6;
|
inp->inp_vflag |= INP_IPV6;
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
INP_HASH_WLOCK(pcbinfo);
|
|
||||||
error = in6_pcbconnect(inp, sin6, td->td_ucred, true);
|
error = in6_pcbconnect(inp, sin6, td->td_ucred, true);
|
||||||
INP_HASH_WUNLOCK(pcbinfo);
|
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
/*
|
/*
|
||||||
* If connect succeeds, mark socket as connected. If
|
* If connect succeeds, mark socket as connected. If
|
||||||
|
|||||||
Reference in New Issue
Block a user