diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-07-30 09:26:27 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-07-30 09:26:27 +0000 |
commit | 13b6ce6962eaf8de9b16589dde1fa06b5947d5f8 (patch) | |
tree | f8f359f7fc34d3a796eb842467eb89cc34d73994 | |
parent | 0c146c189c9a742f1346ef7f1e073813fb958f2c (diff) | |
download | FreeBSD-src-13b6ce6962eaf8de9b16589dde1fa06b5947d5f8.zip FreeBSD-src-13b6ce6962eaf8de9b16589dde1fa06b5947d5f8.tar.gz |
Adopt the slightly weaker consistency locking approach used in IPv4 raw
sockets for IPv6 raw sockets: separately lock the inpcb for determining
the destination address for a connect()'d raw socket at the rip6_send()
layer, and then re-acquire the inpcb lock in the rip6_output() layer to
query other options on the socket. Previously, the global raw IP socket
lock was used, which while correct and marginally more consistent, could
add significantly to global raw IP socket lock contention.
MFC after: 1 week
-rw-r--r-- | sys/netinet6/raw_ip6.c | 10 |
1 files changed, 3 insertions, 7 deletions
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 4f02f32..9a35dc1 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -756,12 +756,10 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip6_send: inp == NULL")); - INP_INFO_WLOCK(&ripcbinfo); /* Always copy sockaddr to avoid overwrites. */ /* Unlocked read. */ if (so->so_state & SS_ISCONNECTED) { if (nam) { - INP_INFO_WUNLOCK(&ripcbinfo); m_freem(m); return (EISCONN); } @@ -769,17 +767,17 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, bzero(&tmp, sizeof(tmp)); tmp.sin6_family = AF_INET6; tmp.sin6_len = sizeof(struct sockaddr_in6); + INP_RLOCK(inp); bcopy(&inp->in6p_faddr, &tmp.sin6_addr, - sizeof(struct in6_addr)); + sizeof(struct in6_addr)); + INP_RUNLOCK(inp); dst = &tmp; } else { if (nam == NULL) { - INP_INFO_WUNLOCK(&ripcbinfo); m_freem(m); return (ENOTCONN); } if (nam->sa_len != sizeof(struct sockaddr_in6)) { - INP_INFO_WUNLOCK(&ripcbinfo); m_freem(m); return (EINVAL); } @@ -796,13 +794,11 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, "unspec. Assume AF_INET6\n"); dst->sin6_family = AF_INET6; } else if (dst->sin6_family != AF_INET6) { - INP_INFO_WUNLOCK(&ripcbinfo); m_freem(m); return(EAFNOSUPPORT); } } ret = rip6_output(m, so, dst, control); - INP_INFO_WUNLOCK(&ripcbinfo); return (ret); } |