Download raw body.
sys/uvm: avoid deadlock in swapctl -d
On Mon, 13 Apr 2026 01:32:19 +0200,
Kirill A. Korinsky <kirill@korins.ky> 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
sys/uvm: avoid deadlock in swapctl -d