Download raw body.
sys/uvm: avoid deadlock in swapctl -d
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
sys/uvm: avoid deadlock in swapctl -d