From 68f17e9b6872a274fd98ed5d52f202e5157b39df Mon Sep 17 00:00:00 2001 From: rwatson Date: Thu, 29 May 2008 08:27:14 +0000 Subject: Employ read locks on UDP inpcbs, rather than write locks, when monitoring UDP connections using sysctls. In some cases, add previously missing locking of inpcbs, as inp_socket is followed, which also allows us to drop global locks more quickly. MFC after: 1 week --- sys/netinet/udp_usrreq.c | 31 ++++++++++++++++++------------- sys/netinet6/udp6_usrreq.c | 23 ++++++++++++----------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index bb40129..ca4c83a 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -669,11 +669,11 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) INP_INFO_RLOCK(&udbinfo); for (inp = LIST_FIRST(udbinfo.ipi_listhead), i = 0; inp && i < n; inp = LIST_NEXT(inp, inp_list)) { - INP_WLOCK(inp); + INP_RLOCK(inp); if (inp->inp_gencnt <= gencnt && cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0) inp_list[i++] = inp; - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); } INP_INFO_RUNLOCK(&udbinfo); n = i; @@ -681,7 +681,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) error = 0; for (i = 0; i < n; i++) { inp = inp_list[i]; - INP_WLOCK(inp); + INP_RLOCK(inp); if (inp->inp_gencnt <= gencnt) { struct xinpcb xi; bzero(&xi, sizeof(xi)); @@ -691,10 +691,10 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) if (inp->inp_socket) sotoxsocket(inp->inp_socket, &xi.xi_socket); xi.xi_inp.inp_gencnt = inp->inp_gencnt; - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); error = SYSCTL_OUT(req, &xi, sizeof xi); } else - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); } if (!error) { /* @@ -734,16 +734,21 @@ udp_getcred(SYSCTL_HANDLER_ARGS) INP_INFO_RLOCK(&udbinfo); inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port, addrs[0].sin_addr, addrs[0].sin_port, 1, NULL); - if (inp == NULL || inp->inp_socket == NULL) { + if (inp != NULL) { + INP_RLOCK(inp); + INP_INFO_RUNLOCK(&udbinfo); + if (inp->inp_socket == NULL) + error = ENOENT; + if (error == 0) + error = cr_canseesocket(req->td->td_ucred, + inp->inp_socket); + if (error == 0) + cru2x(inp->inp_socket->so_cred, &xuc); + INP_RUNLOCK(inp); + } else { + INP_INFO_RUNLOCK(&udbinfo); error = ENOENT; - goto out; } - error = cr_canseesocket(req->td->td_ucred, inp->inp_socket); - if (error) - goto out; - cru2x(inp->inp_socket->so_cred, &xuc); -out: - INP_INFO_RUNLOCK(&udbinfo); if (error == 0) error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); return (error); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 161c274..a3cf3e1 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -449,20 +449,21 @@ udp6_getcred(SYSCTL_HANDLER_ARGS) inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr, addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1, NULL); - if (inp == NULL) { + if (inp != NULL) { + INP_RLOCK(inp); + INP_INFO_RUNLOCK(&udbinfo); + if (inp->inp_socket == NULL) + error = ENOENT; + if (error == 0) + error = cr_canseesocket(req->td->td_ucred, + inp->inp_socket); + if (error == 0) + cru2x(inp->inp_socket->so_cred, &xuc); + INP_RUNLOCK(inp); + } else { INP_INFO_RUNLOCK(&udbinfo); - return (ENOENT); - } - INP_RLOCK(inp); - if (inp->inp_socket == NULL) { error = ENOENT; - goto out; } - error = cr_canseesocket(req->td->td_ucred, inp->inp_socket); - if (error) - goto out; - cru2x(inp->inp_socket->so_cred, &xuc); -out: INP_RUNLOCK(inp); INP_INFO_RUNLOCK(&udbinfo); if (error == 0) -- cgit v1.1