diff options
author | Gleb Smirnoff <glebius@FreeBSD.org> | 2019-11-07 21:27:32 +0000 |
---|---|---|
committer | Gleb Smirnoff <glebius@FreeBSD.org> | 2019-11-07 21:27:32 +0000 |
commit | 032677ceb535e53dcd041eff471a6fee631afe9b (patch) | |
tree | ffee1673969d517e554519465eae3ab04e83028e /sys/netinet/raw_ip.c | |
parent | d40c0d47cd2a8100b8b9719bea092dde0512937a (diff) | |
download | src-032677ceb535e53dcd041eff471a6fee631afe9b.tar.gz src-032677ceb535e53dcd041eff471a6fee631afe9b.zip |
Notes
Diffstat (limited to 'sys/netinet/raw_ip.c')
-rw-r--r-- | sys/netinet/raw_ip.c | 72 |
1 files changed, 21 insertions, 51 deletions
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 1dd7a9de3f56..95f1a7c04b93 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -1067,97 +1067,67 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, static int rip_pcblist(SYSCTL_HANDLER_ARGS) { - int error, i, n; - struct inpcb *inp, **inp_list; - inp_gen_t gencnt; struct xinpgen xig; struct epoch_tracker et; + struct inpcb *inp; + int error; + + if (req->newptr != 0) + return (EPERM); - /* - * The process of preparing the TCB list is too time-consuming and - * resource-intensive to repeat twice on every request. - */ if (req->oldptr == 0) { + int n; + n = V_ripcbinfo.ipi_count; n += imax(n / 8, 10); req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); return (0); } - if (req->newptr != 0) - return (EPERM); - - /* - * OK, now we're committed to doing something. - */ - INP_INFO_WLOCK(&V_ripcbinfo); - gencnt = V_ripcbinfo.ipi_gencnt; - n = V_ripcbinfo.ipi_count; - INP_INFO_WUNLOCK(&V_ripcbinfo); + if ((error = sysctl_wire_old_buffer(req, 0)) != 0) + return (error); bzero(&xig, sizeof(xig)); xig.xig_len = sizeof xig; - xig.xig_count = n; - xig.xig_gen = gencnt; + xig.xig_count = V_ripcbinfo.ipi_count; + xig.xig_gen = V_ripcbinfo.ipi_gencnt; xig.xig_sogen = so_gencnt; error = SYSCTL_OUT(req, &xig, sizeof xig); if (error) return (error); - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); - - INP_INFO_RLOCK_ET(&V_ripcbinfo, et); - for (inp = CK_LIST_FIRST(V_ripcbinfo.ipi_listhead), i = 0; inp && i < n; - inp = CK_LIST_NEXT(inp, inp_list)) { - INP_WLOCK(inp); - if (inp->inp_gencnt <= gencnt && - cr_canseeinpcb(req->td->td_ucred, inp) == 0) { - in_pcbref(inp); - inp_list[i++] = inp; - } - INP_WUNLOCK(inp); - } - INP_INFO_RUNLOCK_ET(&V_ripcbinfo, et); - n = i; - - error = 0; - for (i = 0; i < n; i++) { - inp = inp_list[i]; + NET_EPOCH_ENTER(et); + for (inp = CK_LIST_FIRST(V_ripcbinfo.ipi_listhead); + inp != NULL; + inp = CK_LIST_NEXT(inp, inp_list)) { INP_RLOCK(inp); - if (inp->inp_gencnt <= gencnt) { + if (inp->inp_gencnt <= xig.xig_gen && + cr_canseeinpcb(req->td->td_ucred, inp) == 0) { struct xinpcb xi; in_pcbtoxinpcb(inp, &xi); INP_RUNLOCK(inp); error = SYSCTL_OUT(req, &xi, sizeof xi); + if (error) + break; } else INP_RUNLOCK(inp); } - INP_INFO_WLOCK(&V_ripcbinfo); - for (i = 0; i < n; i++) { - inp = inp_list[i]; - INP_RLOCK(inp); - if (!in_pcbrele_rlocked(inp)) - INP_RUNLOCK(inp); - } - INP_INFO_WUNLOCK(&V_ripcbinfo); + NET_EPOCH_EXIT(et); if (!error) { - struct epoch_tracker et; /* * Give the user an updated idea of our state. If the * generation differs from what we told her before, she knows * that something happened while we were processing this * request, and it might be necessary to retry. */ - INP_INFO_RLOCK_ET(&V_ripcbinfo, et); xig.xig_gen = V_ripcbinfo.ipi_gencnt; xig.xig_sogen = so_gencnt; xig.xig_count = V_ripcbinfo.ipi_count; - INP_INFO_RUNLOCK_ET(&V_ripcbinfo, et); error = SYSCTL_OUT(req, &xig, sizeof xig); } - free(inp_list, M_TEMP); + return (error); } |