Push down pcbinfo and inpcb locking from udp_send() into udp_output().

This provides greater context for the locking and allows us to avoid
locking the pcbinfo structure if not binding operations will take
place (i.e., already bound, connected, and no expliti sendto()
address).
This commit is contained in:
rwatson 2004-08-19 01:13:10 +00:00
parent 224ba75d82
commit eb3ee278bc

View File

@ -729,17 +729,19 @@ udp_output(inp, m, addr, control, td)
int error = 0; int error = 0;
int ipflags; int ipflags;
u_short fport, lport; u_short fport, lport;
int unlock_udbinfo;
INP_LOCK_ASSERT(inp); /*
#ifdef MAC * udp_output() may need to temporarily bind or connect the current
mac_create_mbuf_from_inpcb(inp, m); * inpcb. As such, we don't know up front what inpcb locks we will
#endif * need. Do any work to decide what is needed up front before
* acquiring locks.
*/
if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
error = EMSGSIZE;
if (control) if (control)
m_freem(control); m_freem(control);
goto release; m_freem(m);
return EMSGSIZE;
} }
src.sin_addr.s_addr = INADDR_ANY; src.sin_addr.s_addr = INADDR_ANY;
@ -749,9 +751,9 @@ udp_output(inp, m, addr, control, td)
* is stored in a single mbuf. * is stored in a single mbuf.
*/ */
if (control->m_next) { if (control->m_next) {
error = EINVAL;
m_freem(control); m_freem(control);
goto release; m_freem(m);
return EINVAL;
} }
for (; control->m_len > 0; for (; control->m_len > 0;
control->m_data += CMSG_ALIGN(cm->cmsg_len), control->m_data += CMSG_ALIGN(cm->cmsg_len),
@ -787,8 +789,23 @@ udp_output(inp, m, addr, control, td)
} }
m_freem(control); m_freem(control);
} }
if (error) if (error) {
goto release; m_freem(m);
return error;
}
if (src.sin_addr.s_addr != INADDR_ANY ||
addr != NULL) {
INP_INFO_WLOCK(&udbinfo);
unlock_udbinfo = 1;
} else
unlock_udbinfo = 0;
INP_LOCK(inp);
#ifdef MAC
mac_create_mbuf_from_inpcb(inp, m);
#endif
laddr = inp->inp_laddr; laddr = inp->inp_laddr;
lport = inp->inp_lport; lport = inp->inp_lport;
if (src.sin_addr.s_addr != INADDR_ANY) { if (src.sin_addr.s_addr != INADDR_ANY) {
@ -879,11 +896,17 @@ udp_output(inp, m, addr, control, td)
((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
udpstat.udps_opackets++; udpstat.udps_opackets++;
if (unlock_udbinfo)
INP_INFO_WUNLOCK(&udbinfo);
error = ip_output(m, inp->inp_options, NULL, ipflags, error = ip_output(m, inp->inp_options, NULL, ipflags,
inp->inp_moptions, inp); inp->inp_moptions, inp);
INP_UNLOCK(inp);
return (error); return (error);
release: release:
INP_UNLOCK(inp);
if (unlock_udbinfo)
INP_INFO_WUNLOCK(&udbinfo);
m_freem(m); m_freem(m);
return (error); return (error);
} }
@ -1065,22 +1088,9 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *td) struct mbuf *control, struct thread *td)
{ {
struct inpcb *inp; struct inpcb *inp;
int ret;
INP_INFO_WLOCK(&udbinfo);
inp = sotoinpcb(so); inp = sotoinpcb(so);
if (inp == 0) { return udp_output(inp, m, addr, control, td);
INP_INFO_WUNLOCK(&udbinfo);
m_freem(m);
if (control != NULL)
m_freem(control);
return EINVAL;
}
INP_LOCK(inp);
ret = udp_output(inp, m, addr, control, td);
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&udbinfo);
return ret;
} }
int int