udp: make in_pcbbind_setup() acquire the hash lock internally
Reviewed by: pouria, rrs, markj Differential Revision: https://reviews.freebsd.org/D55973
This commit is contained in:
+56
-43
@@ -714,46 +714,6 @@ in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
int
|
||||
in_pcbbind(struct inpcb *inp, struct sockaddr_in *sin, int flags,
|
||||
struct ucred *cred)
|
||||
{
|
||||
int error;
|
||||
bool anonport;
|
||||
|
||||
KASSERT(sin == NULL || sin->sin_family == AF_INET,
|
||||
("%s: invalid address family for %p", __func__, sin));
|
||||
KASSERT(sin == NULL || sin->sin_len == sizeof(struct sockaddr_in),
|
||||
("%s: invalid address length for %p", __func__, sin));
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
/*
|
||||
* Assign a local port like in_pcb_lport(), but also used with connect()
|
||||
@@ -1016,9 +976,9 @@ in_pcbbind_avail(struct inpcb *inp, const struct in_addr laddr,
|
||||
*
|
||||
* On error, the values of *laddrp and *lportp are not changed.
|
||||
*/
|
||||
int
|
||||
in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, in_addr_t *laddrp,
|
||||
u_short *lportp, int flags, struct ucred *cred)
|
||||
static int
|
||||
in_pcbbind_setup_locked(struct inpcb *inp, struct sockaddr_in *sin,
|
||||
in_addr_t *laddrp, u_short *lportp, int flags, struct ucred *cred)
|
||||
{
|
||||
struct socket *so = inp->inp_socket;
|
||||
struct in_addr laddr;
|
||||
@@ -1082,6 +1042,59 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, in_addr_t *laddrp,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
in_pcbbind_setup(struct inpcb *inp, struct sockaddr_in *sin, in_addr_t *laddrp,
|
||||
u_short *lportp, int flags, struct ucred *cred)
|
||||
{
|
||||
int error;
|
||||
|
||||
INP_HASH_WLOCK(inp->inp_pcbinfo);
|
||||
error = in_pcbbind_setup_locked(inp, sin, laddrp, lportp, flags, cred);
|
||||
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
int
|
||||
in_pcbbind(struct inpcb *inp, struct sockaddr_in *sin, int flags,
|
||||
struct ucred *cred)
|
||||
{
|
||||
int error;
|
||||
bool anonport;
|
||||
|
||||
KASSERT(sin == NULL || sin->sin_family == AF_INET,
|
||||
("%s: invalid address family for %p", __func__, sin));
|
||||
KASSERT(sin == NULL || sin->sin_len == sizeof(struct sockaddr_in),
|
||||
("%s: invalid address length for %p", __func__, sin));
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
||||
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_locked(inp, sin, &inp->inp_laddr.s_addr,
|
||||
&inp->inp_lport, flags, cred);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Connect from a socket to a specified address.
|
||||
* Both address and port must be specified in argument sin.
|
||||
|
||||
@@ -1117,7 +1117,6 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
||||
int len, error = 0;
|
||||
struct in_addr faddr, laddr;
|
||||
struct cmsghdr *cm;
|
||||
struct inpcbinfo *pcbinfo;
|
||||
struct sockaddr_in *sin, src;
|
||||
struct epoch_tracker et;
|
||||
int cscov_partial = 0;
|
||||
@@ -1289,7 +1288,6 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
||||
goto release;
|
||||
|
||||
pr = inp->inp_socket->so_proto->pr_protocol;
|
||||
pcbinfo = udp_get_inpcbinfo(pr);
|
||||
|
||||
/*
|
||||
* If the IP_SENDSRCADDR control message was specified, override the
|
||||
@@ -1310,10 +1308,8 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
||||
inp->inp_vflag |= INP_IPV4;
|
||||
inp->inp_vflag &= ~INP_IPV6;
|
||||
}
|
||||
INP_HASH_WLOCK(pcbinfo);
|
||||
error = in_pcbbind_setup(inp, &src, &laddr.s_addr, &lport,
|
||||
V_udp_bind_all_fibs ? 0 : INPBIND_FIB, td->td_ucred);
|
||||
INP_HASH_WUNLOCK(pcbinfo);
|
||||
if ((flags & PRUS_IPV6) != 0)
|
||||
inp->inp_vflag = vflagsav;
|
||||
if (error)
|
||||
|
||||
Reference in New Issue
Block a user