Index | Thread | Search

From:
renaud@openbsd.org
Subject:
Re: sys/uvm: avoid deadlock in swapctl -d
To:
"Kirill A. Korinsky" <kirill@korins.ky>
Cc:
tech@openbsd.org
Date:
Fri, 12 Jun 2026 10:28:10 +0200

Download raw body.

Thread
On Sat, May 23, 2026 at 11:35:04PM +0200, Kirill A. Korinsky wrote:
> From: "Kirill A. Korinsky" <kirill@korins.ky>
> 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 <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?
> > 

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
>