From: Martin Pieuchot Subject: KASSERT "uvmexp.swpgonly > 0" in uvm_anfree_list() To: mvs@openbsd.org, miod@openbsd.org, robert@openbsd.org Cc: tech@openbsd.org Date: Fri, 5 Apr 2024 16:27:14 +0200 Many over the past months have reported this assertion in different scenarios. All of them involved swapping some pages. I figured out that it is due to an accounting bug in uvm_anon_release(). When that function is called, the given anon has a page attached and it might also have an allocated swap slot. The accounting bugs occurs only when an anon has such allocated swap slot. In such case the wrong path is taken inside uvm_anfree() because `an_page' has been cleared by uvm_pagefree() and the global `uvmexp.swpgonly' counter is decremented. Diff below fixes it. Ok? Index: uvm/uvm_anon.c =================================================================== RCS file: /cvs/src/sys/uvm/uvm_anon.c,v diff -u -p -r1.57 uvm_anon.c --- uvm/uvm_anon.c 27 Oct 2023 19:13:51 -0000 1.57 +++ uvm/uvm_anon.c 31 Mar 2024 06:49:40 -0000 @@ -260,7 +260,8 @@ uvm_anon_release(struct vm_anon *anon) uvm_unlock_pageq(); KASSERT(anon->an_page == NULL); lock = anon->an_lock; - uvm_anfree(anon); + uvm_anon_dropswap(anon); + pool_put(&uvm_anon_pool, anon); rw_exit(lock); /* Note: extra reference is held for PG_RELEASED case. */ rw_obj_free(lock);