summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2008-05-29 08:27:14 +0000
committerrwatson <rwatson@FreeBSD.org>2008-05-29 08:27:14 +0000
commit68f17e9b6872a274fd98ed5d52f202e5157b39df (patch)
tree22388d704d4fc56644136213a5896ab417d441cb
parentc0f6b35a3a61d7db3bbff88e6509740819efee75 (diff)
downloadFreeBSD-src-68f17e9b6872a274fd98ed5d52f202e5157b39df.zip
FreeBSD-src-68f17e9b6872a274fd98ed5d52f202e5157b39df.tar.gz
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
-rw-r--r--sys/netinet/udp_usrreq.c31
-rw-r--r--sys/netinet6/udp6_usrreq.c23
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)
OpenPOWER on IntegriCloud