From: Kirill A. Korinsky Subject: sys/uvm: avoid deadlock in swapctl -d To: OpenBSD tech Date: Mon, 13 Apr 2026 01:32:19 +0200 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? 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