From: renaud@openbsd.org Subject: Re: sys/uvm: avoid deadlock in swapctl -d To: "Kirill A. Korinsky" Cc: tech@openbsd.org Date: Fri, 12 Jun 2026 10:28:10 +0200 On Sat, May 23, 2026 at 11:35:04PM +0200, Kirill A. Korinsky wrote: > From: "Kirill A. Korinsky" > To: tech@openbsd.org > Subject: Re: sys/uvm: avoid deadlock in swapctl -d > Date: Sat, 23 May 2026 23:35:04 +0200 > User-Agent: Wanderlust > > 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? > > I reproduced this on amd64 with a -current GENERIC.MP + WITNESS kernel. With the diff applied, swapctl -d no longer produces the reversal, on the same kernel and the same trigger. So OK renaud@ I was unable to reproduce a crash though. > > 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 >