Re: uvm: gracefully handle transient pmap_enter failure with no swap
Nick Owens <[email protected]> Fri, 24 Jul 2026 00:50:34 -0700
| Newsgroups | gmane.os.openbsd.tech |
|---|---|
| Message-ID | <CAH_zEu4ktLczboYagCMQDPrJB+0KFkcyXt35EeeFoRXA382wcw@mail.gmail.com> |
On Tue, Jul 14, 2026 at 5:25 PM Nick Owens <[email protected]> wrote: > > hi, > > since the pmap_vp_pool structures on arm64/riscv64 are 8K, the > allocations have to go through trylock on the kernel map. > > during fault handling, pmap pool allocations may fail due to kernel map > lock contention with PR_NOWAIT set. on a machine with no swap, > uvm_swapisfull() will always be true and then the fault handler will > return ENOMEM, leading the trap handler to simply SIGKILL the process, > even if there are free pages. > > this changes the kill condition to check uvmexp.free to see if pages are > actually scarce, so that we can fall into the recovery path instead of > slaying processes. > > i've run into this issue running -current inside KVM VMs on both arm64 > and riscv64, and one other person mentioned they had this happen on > physical arm64 hardware (radxa zero 3e). this is most visible during > boot time, where there will be 'Killed' messages interleaved with normal > rc output, and daemons will be dead, library_aslr incomplete, etc. > > this can be reproduced by installing 7.9 or a snapshot on a VM on arm64 > or riscv64 with a single / partition and no swap, and 2 vcpus. > > is this the right approach, or would it be better to make the pmap vp > pool allocations fit in single pages to avoid hitting the kernel map > lock, instead of or in addition to this? > > diff --git a/sys/uvm/uvm_fault.c b/sys/uvm/uvm_fault.c > index 866b378199e..4486b170791 100644 > --- a/sys/uvm/uvm_fault.c > +++ b/sys/uvm/uvm_fault.c > @@ -1139,7 +1139,13 @@ retry: > * as the map may change while we're asleep. > */ > uvmfault_unlockall(ufi, amap, NULL); > - if (uvm_swapisfull()) { > + > + /* > + * uvm_swapisfull() will always be true on swapless systems, so > + * also check if pages are genuinely scarce before giving up > + */ > + if (uvm_swapisfull() && > + atomic_load_sint(&uvmexp.free) < uvmexp.freemin) { > /* XXX instrumentation */ > return ENOMEM; > } > @@ -1517,7 +1523,13 @@ uvm_fault_lower(struct uvm_faultinfo *ufi, struct uvm_faultctx *flt, > atomic_clearbits_int(&pg->pg_flags, PG_BUSY|PG_FAKE|PG_WANTED); > UVM_PAGE_OWN(pg, NULL); > uvmfault_unlockall(ufi, amap, uobj); > - if (uvm_swapisfull()) { > + > + /* > + * uvm_swapisfull() will always be true on swapless systems, so > + * also check if pages are genuinely scarce before giving up > + */ > + if (uvm_swapisfull() && > + atomic_load_sint(&uvmexp.free) < uvmexp.freemin) { > /* XXX instrumentation */ > return (ENOMEM); > } ping