On Wed, Sep 06, 2023 at 01:04:19PM +0100, Martin Pieuchot wrote: > Debugging OOM is hard. UVM uses per-CPU counters and sadly > counters_read(9) needs to allocate memory. This is not acceptable in > ddb(4). As a result I cannot see the content of UVM counters in OOM > situations. > > Diff below introduces a *_static() variant of counters_read(9) that > takes a secondary buffer to avoid calling malloc(9). Is it fine? Do > you have a better idea? Should we make it the default or using the > stack might be a problem?
Instead of adding a second interface I think we could get away with just extending counters_read(9) to take a scratch buffer as an optional fourth parameter: void counters_read(struct cpumem *cm, uint64_t *output, unsigned int n, uint64_t *scratch); "scratch"? "temp"? "tmp"? Anyway, a NULL scratch means "allocate this for me", otherwise you're saying you've brought your own. Obviously the contents of scratch are undefined upon return. This kinda looks like a case where we could annotate these pointers with 'restrict', but I have never fully understood when 'restrict' is appropriate vs. when it is overkill or useless. Index: ./kern/subr_percpu.c =================================================================== RCS file: /cvs/src/sys/kern/subr_percpu.c,v retrieving revision 1.10 diff -u -p -r1.10 subr_percpu.c --- ./kern/subr_percpu.c 3 Oct 2022 14:10:53 -0000 1.10 +++ ./kern/subr_percpu.c 6 Sep 2023 17:18:46 -0000 @@ -159,17 +159,19 @@ counters_free(struct cpumem *cm, unsigne } void -counters_read(struct cpumem *cm, uint64_t *output, unsigned int n) +counters_read(struct cpumem *cm, uint64_t *output, unsigned int n, + uint64_t *scratch) { struct cpumem_iter cmi; - uint64_t *gen, *counters, *temp; + uint64_t *gen, *counters, *temp = scratch; uint64_t enter, leave; unsigned int i; for (i = 0; i < n; i++) output[i] = 0; - temp = mallocarray(n, sizeof(uint64_t), M_TEMP, M_WAITOK); + if (scratch == NULL) + temp = mallocarray(n, sizeof(uint64_t), M_TEMP, M_WAITOK); gen = cpumem_first(&cmi, cm); do { @@ -202,7 +204,8 @@ counters_read(struct cpumem *cm, uint64_ gen = cpumem_next(&cmi, cm); } while (gen != NULL); - free(temp, M_TEMP, n * sizeof(uint64_t)); + if (scratch == NULL) + free(temp, M_TEMP, n * sizeof(uint64_t)); } void @@ -305,7 +308,8 @@ counters_free(struct cpumem *cm, unsigne } void -counters_read(struct cpumem *cm, uint64_t *output, unsigned int n) +counters_read(struct cpumem *cm, uint64_t *output, uint64_t *scratch, + unsigned int n) { uint64_t *counters; unsigned int i; Index: ./kern/kern_sysctl.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.418 diff -u -p -r1.418 kern_sysctl.c --- ./kern/kern_sysctl.c 16 Jul 2023 03:01:31 -0000 1.418 +++ ./kern/kern_sysctl.c 6 Sep 2023 17:18:47 -0000 @@ -519,7 +519,7 @@ kern_sysctl(int *name, u_int namelen, vo unsigned int i; memset(&mbs, 0, sizeof(mbs)); - counters_read(mbstat, counters, MBSTAT_COUNT); + counters_read(mbstat, counters, nitems(counters), NULL); for (i = 0; i < MBSTAT_TYPES; i++) mbs.m_mtypes[i] = counters[i]; Index: ./kern/subr_evcount.c =================================================================== RCS file: /cvs/src/sys/kern/subr_evcount.c,v retrieving revision 1.15 diff -u -p -r1.15 subr_evcount.c --- ./kern/subr_evcount.c 5 Dec 2022 08:58:49 -0000 1.15 +++ ./kern/subr_evcount.c 6 Sep 2023 17:18:47 -0000 @@ -101,7 +101,7 @@ evcount_sysctl(int *name, u_int namelen, { int error = 0, s, nintr, i; struct evcount *ec; - u_int64_t count; + u_int64_t count, scratch; if (newp != NULL) return (EPERM); @@ -129,7 +129,7 @@ evcount_sysctl(int *name, u_int namelen, if (ec == NULL) return (ENOENT); if (ec->ec_percpu != NULL) { - counters_read(ec->ec_percpu, &count, 1); + counters_read(ec->ec_percpu, &count, 1, &scratch); } else { s = splhigh(); count = ec->ec_count; Index: ./net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.707 diff -u -p -r1.707 if.c --- ./net/if.c 18 Aug 2023 08:10:16 -0000 1.707 +++ ./net/if.c 6 Sep 2023 17:18:49 -0000 @@ -2797,7 +2797,8 @@ if_getdata(struct ifnet *ifp, struct if_ if (ifp->if_counters != NULL) { uint64_t counters[ifc_ncounters]; - counters_read(ifp->if_counters, counters, nitems(counters)); + counters_read(ifp->if_counters, counters, nitems(counters), + NULL); data->ifi_ipackets += counters[ifc_ipackets]; data->ifi_ierrors += counters[ifc_ierrors]; Index: ./net/if_etherip.c =================================================================== RCS file: /cvs/src/sys/net/if_etherip.c,v retrieving revision 1.50 diff -u -p -r1.50 if_etherip.c --- ./net/if_etherip.c 28 Feb 2022 00:12:11 -0000 1.50 +++ ./net/if_etherip.c 6 Sep 2023 17:18:51 -0000 @@ -789,7 +789,7 @@ etherip_sysctl_etheripstat(void *oldp, s sizeof(uint64_t))); memset(ðeripstat, 0, sizeof etheripstat); counters_read(etheripcounters, (uint64_t *)ðeripstat, - etherips_ncounters); + etherips_ncounters, NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, ðeripstat, sizeof(etheripstat))); } Index: ./net/if_pfsync.c =================================================================== RCS file: /cvs/src/sys/net/if_pfsync.c,v retrieving revision 1.320 diff -u -p -r1.320 if_pfsync.c --- ./net/if_pfsync.c 18 Aug 2023 08:03:57 -0000 1.320 +++ ./net/if_pfsync.c 6 Sep 2023 17:19:08 -0000 @@ -3339,7 +3339,7 @@ pfsync_sysctl_pfsyncstat(void *oldp, siz CTASSERT(sizeof(pfsyncstat) == (pfsyncs_ncounters * sizeof(uint64_t))); memset(&pfsyncstat, 0, sizeof pfsyncstat); counters_read(pfsynccounters, (uint64_t *)&pfsyncstat, - pfsyncs_ncounters); + pfsyncs_ncounters, NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &pfsyncstat, sizeof(pfsyncstat))); } Index: ./net/pfkeyv2_convert.c =================================================================== RCS file: /cvs/src/sys/net/pfkeyv2_convert.c,v retrieving revision 1.80 diff -u -p -r1.80 pfkeyv2_convert.c --- ./net/pfkeyv2_convert.c 7 Aug 2023 03:35:06 -0000 1.80 +++ ./net/pfkeyv2_convert.c 6 Sep 2023 17:19:09 -0000 @@ -992,7 +992,7 @@ export_counter(void **p, struct tdb *tdb uint64_t counters[tdb_ncounters]; struct sadb_x_counter *scnt = (struct sadb_x_counter *)*p; - counters_read(tdb->tdb_counters, counters, tdb_ncounters); + counters_read(tdb->tdb_counters, counters, tdb_ncounters, NULL); scnt->sadb_x_counter_len = sizeof(struct sadb_x_counter) / sizeof(uint64_t); Index: ./net/pipex.c =================================================================== RCS file: /cvs/src/sys/net/pipex.c,v retrieving revision 1.148 diff -u -p -r1.148 pipex.c --- ./net/pipex.c 30 Aug 2022 19:42:29 -0000 1.148 +++ ./net/pipex.c 6 Sep 2023 17:19:14 -0000 @@ -558,7 +558,7 @@ pipex_export_session_stats(struct pipex_ memset(stats, 0, sizeof(*stats)); - counters_read(session->stat_counters, counters, pxc_ncounters); + counters_read(session->stat_counters, counters, pxc_ncounters, NULL); stats->ipackets = counters[pxc_ipackets]; stats->ierrors = counters[pxc_ierrors]; stats->ibytes = counters[pxc_ibytes]; Index: ./net/rtsock.c =================================================================== RCS file: /cvs/src/sys/net/rtsock.c,v retrieving revision 1.369 diff -u -p -r1.369 rtsock.c --- ./net/rtsock.c 28 Jul 2023 09:33:16 -0000 1.369 +++ ./net/rtsock.c 6 Sep 2023 17:19:15 -0000 @@ -2245,7 +2245,7 @@ sysctl_rtable_rtstat(void *oldp, size_t CTASSERT(sizeof(rtstat) == (nitems(counters) * sizeof(uint32_t))); memset(&rtstat, 0, sizeof rtstat); - counters_read(rtcounters, counters, nitems(counters)); + counters_read(rtcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (uint32_t)counters[i]; Index: ./netinet/igmp.c =================================================================== RCS file: /cvs/src/sys/netinet/igmp.c,v retrieving revision 1.82 diff -u -p -r1.82 igmp.c --- ./netinet/igmp.c 8 Sep 2022 10:22:06 -0000 1.82 +++ ./netinet/igmp.c 6 Sep 2023 17:19:15 -0000 @@ -687,7 +687,7 @@ igmp_sysctl_igmpstat(void *oldp, size_t CTASSERT(sizeof(igmpstat) == (nitems(counters) * sizeof(u_long))); memset(&igmpstat, 0, sizeof igmpstat); - counters_read(igmpcounters, counters, nitems(counters)); + counters_read(igmpcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet/ip_carp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_carp.c,v retrieving revision 1.357 diff -u -p -r1.357 ip_carp.c --- ./netinet/ip_carp.c 16 May 2023 14:32:54 -0000 1.357 +++ ./netinet/ip_carp.c 6 Sep 2023 17:19:15 -0000 @@ -749,7 +749,8 @@ carp_sysctl_carpstat(void *oldp, size_t CTASSERT(sizeof(carpstat) == (carps_ncounters * sizeof(uint64_t))); memset(&carpstat, 0, sizeof carpstat); - counters_read(carpcounters, (uint64_t *)&carpstat, carps_ncounters); + counters_read(carpcounters, (uint64_t *)&carpstat, carps_ncounters, + NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &carpstat, sizeof(carpstat))); } Index: ./netinet/ip_divert.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_divert.c,v retrieving revision 1.91 diff -u -p -r1.91 ip_divert.c --- ./netinet/ip_divert.c 13 May 2023 13:35:17 -0000 1.91 +++ ./netinet/ip_divert.c 6 Sep 2023 17:19:15 -0000 @@ -350,7 +350,7 @@ divert_sysctl_divstat(void *oldp, size_t CTASSERT(sizeof(divstat) == (nitems(counters) * sizeof(u_long))); memset(&divstat, 0, sizeof divstat); - counters_read(divcounters, counters, nitems(counters)); + counters_read(divcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet/ip_icmp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.191 diff -u -p -r1.191 ip_icmp.c --- ./netinet/ip_icmp.c 5 May 2022 13:57:40 -0000 1.191 +++ ./netinet/ip_icmp.c 6 Sep 2023 17:19:15 -0000 @@ -917,7 +917,7 @@ icmp_sysctl_icmpstat(void *oldp, size_t CTASSERT(sizeof(icmpstat) == (nitems(counters) * sizeof(u_long))); memset(&icmpstat, 0, sizeof icmpstat); - counters_read(icmpcounters, counters, nitems(counters)); + counters_read(icmpcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet/ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.385 diff -u -p -r1.385 ip_input.c --- ./netinet/ip_input.c 18 May 2023 09:59:43 -0000 1.385 +++ ./netinet/ip_input.c 6 Sep 2023 17:19:15 -0000 @@ -1747,7 +1747,7 @@ ip_sysctl_ipstat(void *oldp, size_t *old CTASSERT(sizeof(ipstat) == (nitems(counters) * sizeof(u_long))); memset(&ipstat, 0, sizeof ipstat); - counters_read(ipcounters, counters, nitems(counters)); + counters_read(ipcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet/ip_ipip.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_ipip.c,v retrieving revision 1.98 diff -u -p -r1.98 ip_ipip.c --- ./netinet/ip_ipip.c 2 Jan 2022 22:36:04 -0000 1.98 +++ ./netinet/ip_ipip.c 6 Sep 2023 17:19:16 -0000 @@ -573,7 +573,8 @@ ipip_sysctl_ipipstat(void *oldp, size_t CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t))); memset(&ipipstat, 0, sizeof ipipstat); - counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters); + counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters, + NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &ipipstat, sizeof(ipipstat))); } Index: ./netinet/ipsec_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ipsec_input.c,v retrieving revision 1.205 diff -u -p -r1.205 ipsec_input.c --- ./netinet/ipsec_input.c 7 Aug 2023 03:43:57 -0000 1.205 +++ ./netinet/ipsec_input.c 6 Sep 2023 17:19:16 -0000 @@ -664,7 +664,7 @@ esp_sysctl_espstat(void *oldp, size_t *o CTASSERT(sizeof(espstat) == (esps_ncounters * sizeof(uint64_t))); memset(&espstat, 0, sizeof espstat); - counters_read(espcounters, (uint64_t *)&espstat, esps_ncounters); + counters_read(espcounters, (uint64_t *)&espstat, esps_ncounters, NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &espstat, sizeof(espstat))); } @@ -698,7 +698,7 @@ ah_sysctl_ahstat(void *oldp, size_t *old CTASSERT(sizeof(ahstat) == (ahs_ncounters * sizeof(uint64_t))); memset(&ahstat, 0, sizeof ahstat); - counters_read(ahcounters, (uint64_t *)&ahstat, ahs_ncounters); + counters_read(ahcounters, (uint64_t *)&ahstat, ahs_ncounters, NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &ahstat, sizeof(ahstat))); } @@ -733,7 +733,7 @@ ipcomp_sysctl_ipcompstat(void *oldp, siz CTASSERT(sizeof(ipcompstat) == (ipcomps_ncounters * sizeof(uint64_t))); memset(&ipcompstat, 0, sizeof ipcompstat); counters_read(ipcompcounters, (uint64_t *)&ipcompstat, - ipcomps_ncounters); + ipcomps_ncounters, NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &ipcompstat, sizeof(ipcompstat))); } @@ -745,7 +745,8 @@ ipsec_sysctl_ipsecstat(void *oldp, size_ CTASSERT(sizeof(ipsecstat) == (ipsec_ncounters * sizeof(uint64_t))); memset(&ipsecstat, 0, sizeof ipsecstat); - counters_read(ipseccounters, (uint64_t *)&ipsecstat, ipsec_ncounters); + counters_read(ipseccounters, (uint64_t *)&ipsecstat, ipsec_ncounters, + NULL); return (sysctl_rdstruct(oldp, oldlenp, newp, &ipsecstat, sizeof(ipsecstat))); } Index: ./netinet/tcp_usrreq.c =================================================================== RCS file: /cvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.221 diff -u -p -r1.221 tcp_usrreq.c --- ./netinet/tcp_usrreq.c 6 Jul 2023 09:15:24 -0000 1.221 +++ ./netinet/tcp_usrreq.c 6 Sep 2023 17:19:17 -0000 @@ -1237,7 +1237,7 @@ tcp_sysctl_tcpstat(void *oldp, size_t *o #define ASSIGN(field) do { tcpstat.field = counters[i++]; } while (0) memset(&tcpstat, 0, sizeof tcpstat); - counters_read(tcpcounters, counters, nitems(counters)); + counters_read(tcpcounters, counters, nitems(counters), NULL); ASSIGN(tcps_connattempt); ASSIGN(tcps_accepts); ASSIGN(tcps_connects); Index: ./netinet/udp_usrreq.c =================================================================== RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.305 diff -u -p -r1.305 udp_usrreq.c --- ./netinet/udp_usrreq.c 22 Jan 2023 12:05:44 -0000 1.305 +++ ./netinet/udp_usrreq.c 6 Sep 2023 17:19:17 -0000 @@ -1314,7 +1314,7 @@ udp_sysctl_udpstat(void *oldp, size_t *o CTASSERT(sizeof(udpstat) == (nitems(counters) * sizeof(u_long))); memset(&udpstat, 0, sizeof udpstat); - counters_read(udpcounters, counters, nitems(counters)); + counters_read(udpcounters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet6/icmp6.c =================================================================== RCS file: /cvs/src/sys/netinet6/icmp6.c,v retrieving revision 1.248 diff -u -p -r1.248 icmp6.c --- ./netinet6/icmp6.c 5 Apr 2023 21:51:47 -0000 1.248 +++ ./netinet6/icmp6.c 6 Sep 2023 17:19:17 -0000 @@ -1870,7 +1870,8 @@ icmp6_sysctl_icmp6stat(void *oldp, size_ CTASSERT(sizeof(*icmp6stat) == icp6s_ncounters * sizeof(uint64_t)); icmp6stat = malloc(sizeof(*icmp6stat), M_TEMP, M_WAITOK|M_ZERO); - counters_read(icmp6counters, (uint64_t *)icmp6stat, icp6s_ncounters); + counters_read(icmp6counters, (uint64_t *)icmp6stat, icp6s_ncounters, + NULL); ret = sysctl_rdstruct(oldp, oldlenp, newp, icmp6stat, sizeof(*icmp6stat)); free(icmp6stat, M_TEMP, sizeof(*icmp6stat)); Index: ./netinet6/ip6_divert.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_divert.c,v retrieving revision 1.89 diff -u -p -r1.89 ip6_divert.c --- ./netinet6/ip6_divert.c 4 Apr 2023 10:12:03 -0000 1.89 +++ ./netinet6/ip6_divert.c 6 Sep 2023 17:19:18 -0000 @@ -358,7 +358,7 @@ divert6_sysctl_div6stat(void *oldp, size CTASSERT(sizeof(div6stat) == (nitems(counters) * sizeof(u_long))); - counters_read(div6counters, counters, nitems(counters)); + counters_read(div6counters, counters, nitems(counters), NULL); for (i = 0; i < nitems(counters); i++) words[i] = (u_long)counters[i]; Index: ./netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.254 diff -u -p -r1.254 ip6_input.c --- ./netinet6/ip6_input.c 21 Aug 2022 14:15:55 -0000 1.254 +++ ./netinet6/ip6_input.c 6 Sep 2023 17:19:19 -0000 @@ -1466,7 +1466,7 @@ ip6_sysctl_ip6stat(void *oldp, size_t *o CTASSERT(sizeof(*ip6stat) == (ip6s_ncounters * sizeof(uint64_t))); ip6stat = malloc(sizeof(*ip6stat), M_TEMP, M_WAITOK); - counters_read(ip6counters, (uint64_t *)ip6stat, ip6s_ncounters); + counters_read(ip6counters, (uint64_t *)ip6stat, ip6s_ncounters, NULL); ret = sysctl_rdstruct(oldp, oldlenp, newp, ip6stat, sizeof(*ip6stat)); free(ip6stat, M_TEMP, sizeof(*ip6stat)); Index: ./netinet6/raw_ip6.c =================================================================== RCS file: /cvs/src/sys/netinet6/raw_ip6.c,v retrieving revision 1.172 diff -u -p -r1.172 raw_ip6.c --- ./netinet6/raw_ip6.c 22 Jan 2023 12:05:44 -0000 1.172 +++ ./netinet6/raw_ip6.c 6 Sep 2023 17:19:19 -0000 @@ -784,7 +784,8 @@ rip6_sysctl_rip6stat(void *oldp, size_t struct rip6stat rip6stat; CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t)); - counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters); + counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters, + NULL); return (sysctl_rdstruct(oldp, oldplen, newp, &rip6stat, sizeof(rip6stat))); Index: ./sys/percpu.h =================================================================== RCS file: /cvs/src/sys/sys/percpu.h,v retrieving revision 1.8 diff -u -p -r1.8 percpu.h --- ./sys/percpu.h 28 Aug 2018 15:15:02 -0000 1.8 +++ ./sys/percpu.h 6 Sep 2023 17:19:19 -0000 @@ -113,7 +113,8 @@ static struct { \ struct cpumem *counters_alloc(unsigned int); struct cpumem *counters_alloc_ncpus(struct cpumem *, unsigned int); void counters_free(struct cpumem *, unsigned int); -void counters_read(struct cpumem *, uint64_t *, unsigned int); +void counters_read(struct cpumem *, uint64_t *, unsigned int, + uint64_t *); void counters_zero(struct cpumem *, unsigned int); static inline uint64_t * Index: ./uvm/uvm_meter.c =================================================================== RCS file: /cvs/src/sys/uvm/uvm_meter.c,v retrieving revision 1.49 diff -u -p -r1.49 uvm_meter.c --- ./uvm/uvm_meter.c 18 Aug 2023 09:18:52 -0000 1.49 +++ ./uvm/uvm_meter.c 6 Sep 2023 17:19:19 -0000 @@ -249,11 +249,11 @@ uvm_total(struct vmtotal *totalp) void uvmexp_read(struct uvmexp *uexp) { - uint64_t counters[exp_ncounters]; + uint64_t counters[exp_ncounters], tmp[exp_ncounters]; memcpy(uexp, &uvmexp, sizeof(*uexp)); - counters_read(uvmexp_counters, counters, exp_ncounters); + counters_read(uvmexp_counters, counters, exp_ncounters, tmp); /* stat counters */ uexp->faults = (int)counters[faults];