diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-05-29 14:28:26 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-05-29 14:28:26 +0000 |
commit | 4ab736a48e0210d0590c2f490c981f7b6d60a697 (patch) | |
tree | e6e1196ef44b7badc4f87fe1fe8687f74651f31f /sys/netinet/tcp_subr.c | |
parent | 5de6a45e07a5027a8c6df5a9c354fbfd9c76aec1 (diff) | |
download | FreeBSD-src-4ab736a48e0210d0590c2f490c981f7b6d60a697.zip FreeBSD-src-4ab736a48e0210d0590c2f490c981f7b6d60a697.tar.gz |
Read lock rather than write lock TCP inpcbs in monitoring sysctls. In
some cases, add explicit inpcb locking rather than relying on the global
lock, as we dereference inp_socket, but also allowing us to drop the
global lock more quickly.
MFC after: 1 week
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r-- | sys/netinet/tcp_subr.c | 66 |
1 files changed, 31 insertions, 35 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 36422197..cb2d89a 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -946,7 +946,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) INP_INFO_RLOCK(&tcbinfo); for (inp = LIST_FIRST(tcbinfo.ipi_listhead), i = 0; inp != NULL && i < n; inp = LIST_NEXT(inp, inp_list)) { - INP_WLOCK(inp); + INP_RLOCK(inp); if (inp->inp_gencnt <= gencnt) { /* * XXX: This use of cr_cansee(), introduced with @@ -965,7 +965,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) if (error == 0) inp_list[i++] = inp; } - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); } INP_INFO_RUNLOCK(&tcbinfo); n = i; @@ -973,7 +973,7 @@ tcp_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 xtcpcb xt; void *inp_ppcb; @@ -997,10 +997,10 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) xt.xt_socket.xso_protocol = IPPROTO_TCP; } xt.xt_inp.inp_gencnt = inp->inp_gencnt; - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); error = SYSCTL_OUT(req, &xt, sizeof xt); } else - INP_WUNLOCK(inp); + INP_RUNLOCK(inp); } if (!error) { @@ -1042,23 +1042,21 @@ tcp_getcred(SYSCTL_HANDLER_ARGS) INP_INFO_RLOCK(&tcbinfo); inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port, addrs[0].sin_addr, addrs[0].sin_port, 0, NULL); - if (inp == NULL) { - error = ENOENT; - goto outunlocked; - } - INP_WLOCK(inp); - if (inp->inp_socket == NULL) { + if (inp != NULL) { + INP_RLOCK(inp); + INP_INFO_RUNLOCK(&tcbinfo); + 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(&tcbinfo); 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_WUNLOCK(inp); -outunlocked: - INP_INFO_RUNLOCK(&tcbinfo); if (error == 0) error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); return (error); @@ -1106,23 +1104,21 @@ tcp6_getcred(SYSCTL_HANDLER_ARGS) inp = in6_pcblookup_hash(&tcbinfo, &addrs[1].sin6_addr, addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 0, NULL); - if (inp == NULL) { - error = ENOENT; - goto outunlocked; - } - INP_WLOCK(inp); - if (inp->inp_socket == NULL) { + if (inp != NULL) { + INP_RLOCK(inp); + INP_INFO_RUNLOCK(&tcbinfo); + 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(&tcbinfo); 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_WUNLOCK(inp); -outunlocked: - INP_INFO_RUNLOCK(&tcbinfo); if (error == 0) error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); return (error); |