NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/60584: vfs_bio: getnewbuf() can deadlock when fresh allocation is refused and no buffer is reclaimable
>Number: 60584
>Category: kern
>Synopsis: vfs_bio: getnewbuf() can deadlock when fresh allocation is refused and no buffer is reclaimable
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Aug 14 05:30:01 +0000 2026
>Originator: Izumi Tsutsui
>Release: NetBSD 11.99.7
>Organization:
>Environment:
NetBSD libero 11.99.7 NetBSD 11.99.7 (GENERIC) #24: Thu Aug 13 09:21:55 JST 2026 tsutsui@mirage:/s/cvs/src/sys/arch/news68k/compile/GENERIC news68k
Architecture: m68k
Machine: news68k, Sony NWS-1750 (MC68030 16MB RAM, 8KB/page)
>Description:
getnewbuf() can deadlock when buf_lotsfree() decides not to allocate
a new buffer and there is no buffer which can actually be reclaimed
from BQ_AGE or BQ_LRU.
getnewbuf() first uses buf_lotsfree() to decide whether to try a fresh
allocation. If fresh allocation is not attempted or fails, it tries
to recycle a buffer from BQ_AGE or BQ_LRU. If no suitable buffer is
available there, it sleeps on needbuffer_cv.
In this case, there is no guarantee that a reclaimable buffer will
eventually become available. Buffers may instead be busy or locked,
for example by WAPBL. A thread which could release such a buffer
may itself need another buffer before it can make progress.
Then a buffer allocation policy decision can turn into a deadlock.
getnewbuf() waits for a buffer to become available while the operation
which could make one available is itself waiting for another buffer.
I observed this on NetBSD/news68k on 16MB NWS-1750 under heavy memory
pressure with WAPBL enabled. makemandb and the pagedaemon were both
sleeping in getnewbuf() on needbuffer_cv, while multiple user
processes were waiting for physical memory.
As a diagnostic experiment in DDB, I temporarily raised
bufmem_lowater so that buf_lotsfree() would permit fresh allocation,
woke the needbuffer_cv waiters, and continued execution.
After that, the machine immediately resumed normal operation.
The pagedaemon started making progress again, free memory increased,
and the affected user processes continued running.
This appears to demonstrate that getnewbuf() has no forward-progress
path when fresh allocation is refused and no buffer can actually be
reclaimed.
I have also previously observed system hangs after decreasing
vm.bufcache at runtime on low-memory machines. The vm.bufcache sysctl
handler changes the buffer cache watermarks and attempts to drain the
cache, but it can return successfully even if the cache cannot be
drained below the new high-water mark.
This may provide an easier way to trigger the same problem, but
I have not yet verified that the older vm.bufcache hang is caused
by this same bug.
>How-To-Repeat:
The exact workload required to reproduce the problem has not been
minimized.
The problem can occur when buf_lotsfree() rejects fresh allocation,
no suitable buffer is available from BQ_AGE or BQ_LRU, and releasing
the buffers needed for forward progress requires another buffer
allocation.
>Fix:
Yes, please.
getnewbuf() appears to need a forward-progress mechanism for the case
where fresh allocation is refused but no buffer can actually be reclaimed.
The appropriate fix might be to reconsider fresh allocation after
reclamation fails, change the allocation policy, reserve resources
needed for forward progress, or change the handling of locked buffers.
I am not sure which approach is appropriate, and would prefer to leave
the decision to people more familiar with the buffer cache and UVM.
---
Izumi Tsutsui
Home |
Main Index |
Thread Index |
Old Index