From: Kirill A. Korinsky Subject: Re: sys/uvm: avoid deadlock in swapctl -d To: tech@openbsd.org Date: Sat, 23 May 2026 23:35:04 +0200 On Mon, 13 Apr 2026 01:32:19 +0200, Kirill A. Korinsky wrote: > > tech@, > > I had noticed a deadlock which is possible to triger via swapctl -d. > > To reproduce it, add to /etc/fstab someting like that: > > 172.31.2.23:/volume1/octeon/swap.octeon none swap sw,nfsmntpt=/swap > > And now just run swapctl -d /swap > > For example with MP_LOCKDEBUG and WITNESS kernel I do have: > > octeon$ doas sync; doas swapctl; doas swapctl -d /swap > Device 512-blocks Used Avail Capacity Priority > /swap 33554432 0 33554432 0% 0 > witness: lock order reversal: > 1st 0xffffffff816be9f8 amaplstlk (amaplstlk) > 2nd 0x9800000419227688 amaplk (&amap->am_lock) > lock order [1] amaplstlk (amaplstlk) -> [2] amaplk (&amap->am_lock) > #0 witness_checkorder+0x50c > #1 rw_do_enter_write+0x84 > #2 rw_enter+0x78 > #3 amap_swap_off+0xb8 > #4 swap_off+0x120 > #5 sys_swapctl+0x448 > #6 itsa+0x118c > #7 trap+0x1f8 > #8 u_general+0xd8 > lock order [2] amaplk (&amap->am_lock) -> [1] amaplstlk (amaplstlk) > #0 witness_checkorder+0x50c > #1 rw_do_enter_write+0x84 > #2 rw_enter_write+0x30 > #3 amap_wipeout+0x98 > #4 amap_unref+0x84 > #5 uvm_unmap_detach+0xcc > #6 uvmspace_exec+0x218 > #7 sys_execve+0x6cc > #8 start_init+0x338 > #9 proc_trampoline+0x1c > Stopped at db_enter+0x4: jr ra > db_enter+0x8: nop > ddb{0}> > > I had encountered crashes from swapctl -d a while ago: > https://marc.info/?l=openbsd-bugs&m=172195369905445&w=2 > but I not sure that it is related. > > Thouhgs? OK? > Anyone? Index: sys/uvm/uvm_amap.c =================================================================== RCS file: /home/cvs/src/sys/uvm/uvm_amap.c,v diff -u -p -r1.98 uvm_amap.c --- sys/uvm/uvm_amap.c 10 Dec 2025 08:38:18 -0000 1.98 +++ sys/uvm/uvm_amap.c 12 Apr 2026 23:16:06 -0000 @@ -478,8 +478,6 @@ amap_wipeout(struct vm_amap *amap) return; } - amap_list_remove(amap); - AMAP_CHUNK_FOREACH(chunk, amap) { int i, refs, map = chunk->ac_usedmap; @@ -1063,7 +1061,7 @@ amap_swap_off(int startslot, int endslot struct vm_amap_chunk *chunk; amap_lock(am, RW_WRITE); - if (am->am_nused == 0) { + if (am->am_ref == 0 || am->am_nused == 0) { amap_unlock(am); am_next = LIST_NEXT(am, am_list); continue; @@ -1096,6 +1094,9 @@ again: am->am_flags &= ~AMAP_SWAPOFF; if (amap_refs(am) == 0) { + amap_unlock(am); + amap_list_remove(am); + amap_lock(am, RW_WRITE); amap_wipeout(am); am = NULL; goto nextamap; @@ -1333,6 +1334,13 @@ amap_unref(struct vm_amap *amap, vaddr_t * If the last reference - wipeout and destroy the amap. */ amap->am_ref--; + if ((amap->am_flags & AMAP_SWAPOFF) != 0) { + amap_wipeout(amap); + return; + } + amap_unlock(amap); + amap_list_remove(amap); + amap_lock(amap, RW_WRITE); amap_wipeout(amap); return; } -- wbr, Kirill