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?
Thanks,
Martin
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 11:54:31 -0000
@@ -161,15 +161,25 @@ counters_free(struct cpumem *cm, unsigne
void
counters_read(struct cpumem *cm, uint64_t *output, unsigned int n)
{
- struct cpumem_iter cmi;
- uint64_t *gen, *counters, *temp;
- uint64_t enter, leave;
+ uint64_t *temp;
unsigned int i;
for (i = 0; i < n; i++)
output[i] = 0;
temp = mallocarray(n, sizeof(uint64_t), M_TEMP, M_WAITOK);
+ counters_read_static(cm, output, n, temp);
+ free(temp, M_TEMP, n * sizeof(uint64_t));
+}
+
+void
+counters_read_static(struct cpumem *cm, uint64_t *output, unsigned int n,
+ uint64_t *temp)
+{
+ struct cpumem_iter cmi;
+ uint64_t *gen, *counters;
+ uint64_t enter, leave;
+ unsigned int i;
gen = cpumem_first(&cmi, cm);
do {
@@ -201,8 +211,6 @@ counters_read(struct cpumem *cm, uint64_
gen = cpumem_next(&cmi, cm);
} while (gen != NULL);
-
- free(temp, M_TEMP, n * sizeof(uint64_t));
}
void
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 11:52:55 -0000
@@ -114,6 +114,8 @@ struct cpumem *counters_alloc(unsigned i
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_static(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 11:53:02 -0000
@@ -249,11 +249,12 @@ uvm_total(struct vmtotal *totalp)
void
uvmexp_read(struct uvmexp *uexp)
{
- uint64_t counters[exp_ncounters];
+ uint64_t counters[exp_ncounters], temp[exp_ncounters];
memcpy(uexp, &uvmexp, sizeof(*uexp));
- counters_read(uvmexp_counters, counters, exp_ncounters);
+ counters_read_static(uvmexp_counters, counters, exp_ncounters,
+ temp);
/* stat counters */
uexp->faults = (int)counters[faults];