Re: sys/uvm: avoid deadlock in swapctl -d

[email protected]
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
On Sat, May 23, 2026 at 11:35:04PM +0200, Kirill A. Korinsky wrote:
> From: "Kirill A. Korinsky" <[email protected]>
> To: [email protected]
> 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 <[email protected]> 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
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.