[Bug 296835] kern: coredump of a process with many EVFILT_VNODE knotes hangs for hours, process unkillable (SIGKILL pending), holds fd table lock (NT_PROCSTAT_KQUEUES note generation)

From: <bugzilla-noreply_at_freebsd.org>
Date: Thu, 16 Jul 2026 12:06:12 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=296835

--- Comment #1 from delleceste@gmail.com ---
## Follow-up comment (posted after filing): why it takes hours — sbuf growth is
O(n^2)

Further live measurement explains the pathological duration. The sizing-pass
sbuf in kern_proc_kqueues_out() is SBUF_AUTOEXTEND, and kernel sbuf extension
(sys/kern/subr_sbuf.c) stops doubling at SBUF_MAXEXTENDSIZE = PAGE_SIZE:

```c
        if (size < (int)SBUF_MAXEXTENDSIZE) {
                newsize = SBUF_MINEXTENDSIZE;
                while (newsize < size)
                        newsize *= 2;
        } else {
                newsize = roundup2(size, SBUF_MAXEXTENDINCR);   /* 4 KB steps
*/
        }
```

and sbuf_extend() does SBMALLOC(newsize) + memcpy(entire buffer) + SBFREE
on every extension. So past 4 KB the buffer grows in 4 KB increments, and
each increment reallocates and copies the whole (now hundreds of MB) buffer:
O(n^2) in the note size, with a full malloc_large page-allocation/free churn
per 4 KB of progress.

Observed on the live process (signal at 11:04):

- 11:38  sbuf = 284 MB, vmstat -m sbuf req rate ~16/s (= 4 KB × 16 = 64 KB/s)
- 13:50  sbuf = 639 MB, 174 min of CPU time consumed, core file still 0 bytes,
  progress rate decayed linearly with buffer size (~330 KB/s at 200 MB,
  ~64 KB/s at 640 MB) — one CPU 100% busy memcpy'ing the buffer once per
  4 KB appended.

At ~780 MB final note size this is roughly 190,000 reallocations copying an
average of ~390 MB each — tens of petabytes of memcpy for the sizing pass
alone. This turns what could be a seconds-long dump into many hours.

This also suggests the smallest fix with the biggest effect: make
kern_proc_kqueues_out() honor the caller's drain (sbuf_count_drain for the
sizing pass, the core vnode drain for the emit pass) instead of accumulating
into a private SBUF_AUTOEXTEND sbuf — the O(n^2) growth, the ~780 MB×2
allocations, and most of the wall-clock time all disappear. Independently,
sbuf's 4 KB linear extension policy is a footgun for any large in-kernel
sbuf consumer.

-- 
You are receiving this mail because:
You are the assignee for the bug.