summaryrefslogtreecommitdiffstats
path: root/sys/netinet/udp_usrreq.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2004-08-19 01:13:10 +0000
committerrwatson <rwatson@FreeBSD.org>2004-08-19 01:13:10 +0000
commiteb3ee278bcf97fff45e19e3ad7f70bc3a318208a (patch)
treeb045bb182d34841feaf04ae2858363b74e10dc92 /sys/netinet/udp_usrreq.c
parent224ba75d82905066375194a21fcfd52c4b6afc1b (diff)
downloadFreeBSD-src-eb3ee278bcf97fff45e19e3ad7f70bc3a318208a.zip
FreeBSD-src-eb3ee278bcf97fff45e19e3ad7f70bc3a318208a.tar.gz
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).
Diffstat (limited to 'sys/netinet/udp_usrreq.c')
-rw-r--r--sys/netinet/udp_usrreq.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index fec2b1c..5f1a1bb 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -729,17 +729,19 @@ udp_output(inp, m, addr, control, td)
int error = 0;
int ipflags;
u_short fport, lport;
+ int unlock_udbinfo;
- INP_LOCK_ASSERT(inp);
-#ifdef MAC
- mac_create_mbuf_from_inpcb(inp, m);
-#endif
-
+ /*
+ * udp_output() may need to temporarily bind or connect the current
+ * inpcb. As such, we don't know up front what inpcb locks we will
+ * need. Do any work to decide what is needed up front before
+ * acquiring locks.
+ */
if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
- error = EMSGSIZE;
if (control)
m_freem(control);
- goto release;
+ m_freem(m);
+ return EMSGSIZE;
}
src.sin_addr.s_addr = INADDR_ANY;
@@ -749,9 +751,9 @@ udp_output(inp, m, addr, control, td)
* is stored in a single mbuf.
*/
if (control->m_next) {
- error = EINVAL;
m_freem(control);
- goto release;
+ m_freem(m);
+ return EINVAL;
}
for (; control->m_len > 0;
control->m_data += CMSG_ALIGN(cm->cmsg_len),
@@ -787,8 +789,23 @@ udp_output(inp, m, addr, control, td)
}
m_freem(control);
}
- if (error)
- goto release;
+ if (error) {
+ 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;
lport = inp->inp_lport;
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 */
udpstat.udps_opackets++;
+ if (unlock_udbinfo)
+ INP_INFO_WUNLOCK(&udbinfo);
error = ip_output(m, inp->inp_options, NULL, ipflags,
inp->inp_moptions, inp);
+ INP_UNLOCK(inp);
return (error);
release:
+ INP_UNLOCK(inp);
+ if (unlock_udbinfo)
+ INP_INFO_WUNLOCK(&udbinfo);
m_freem(m);
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 inpcb *inp;
- int ret;
- INP_INFO_WLOCK(&udbinfo);
inp = sotoinpcb(so);
- if (inp == 0) {
- 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;
+ return udp_output(inp, m, addr, control, td);
}
int
OpenPOWER on IntegriCloud