Re: powerpc64/pmap.c trouble report

Jeremie Courreges-Anglas <[email protected]> Tue, 21 May 2024 03:08:49 +0200
Newsgroups gmane.os.openbsd.ppc,gmane.os.openbsd.bugs
Message-ID <[email protected]>
On Tue, May 21, 2024 at 02:51:39AM +0200, Jeremie Courreges-Anglas wrote:
> On Sat, May 18, 2024 at 01:11:56PM -0700, Eric Grosse wrote:
> > The openbsd-ppc64-n2vi Go builder machine is converting over to LUCI
> > build infrastructure and the new workload may have stepped on a
> > pagedaemon corner case. While running 7.5-stable I reproducibly get
> > kernel panics "pmap_enter: failed to allocate pted". I saw recent
> > powerpc64/pmap.c changes from gkoehler@ and kettenis@, so updated the
> > machine to 7.5-snapshot and now see "trap type 300" from pmap_remove.
> 
> Is that also reproducible?  cc'ing bugs@.
> 
> > In an effort to reproduce this with a more familiar workload, I tried
> > "/usr/src$ make -j32 build" to pound on the hardware with a similar
> > load average and temperature, but that runs without crashing. I'd
> > welcome suggestions on anything I can do to reduce this to a useful
> > bug report.
> > 
> > https://n2vi.com/t.dmesg   latest dmesg
> > https://n2vi.com/t.crash1   ddb serial console from the 7.5-stable panics
> 
> This doesn't look powerpc64-specific.  It feels like
> uvm_km_kmemalloc_pla() should call pmap_enter() with PMAP_CANFAIL and
> unwind in case of a resource shortage.

The diff below behaves when I inject fake pmap_enter() failures on
amd64.  It would be nice to test it on -stable and/or -current,
depending on whether it happens on -stable only or also on -current.


diff --git a/sys/uvm/uvm_km.c b/sys/uvm/uvm_km.c
index a715173529a..3779ea3d7ee 100644
--- a/sys/uvm/uvm_km.c
+++ b/sys/uvm/uvm_km.c
@@ -335,7 +335,7 @@ uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size,
 	vaddr_t kva, loopva;
 	voff_t offset;
 	struct vm_page *pg;
-	struct pglist pgl;
+	struct pglist pgl, pgldone;
 	int pla_flags;
 
 	KASSERT(vm_map_pmap(map) == pmap_kernel());
@@ -372,6 +372,7 @@ uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size,
 	 * whom should ever get a handle on this area of VM.
 	 */
 	TAILQ_INIT(&pgl);
+	TAILQ_INIT(&pgldone);
 	pla_flags = 0;
 	KASSERT(uvmexp.swpgonly <= uvmexp.swpages);
 	if ((flags & UVM_KMF_NOWAIT) ||
@@ -396,6 +397,7 @@ uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size,
 	while (loopva != kva + size) {
 		pg = TAILQ_FIRST(&pgl);
 		TAILQ_REMOVE(&pgl, pg, pageq);
+		TAILQ_INSERT_TAIL(&pgldone, pg, pageq);
 		uvm_pagealloc_pg(pg, obj, offset, NULL);
 		atomic_clearbits_int(&pg->pg_flags, PG_BUSY);
 		UVM_PAGE_OWN(pg, NULL);
@@ -408,9 +410,28 @@ uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size,
 			pmap_kenter_pa(loopva, VM_PAGE_TO_PHYS(pg),
 			    PROT_READ | PROT_WRITE);
 		} else {
-			pmap_enter(map->pmap, loopva, VM_PAGE_TO_PHYS(pg),
+			if (pmap_enter(map->pmap, loopva, VM_PAGE_TO_PHYS(pg),
 			    PROT_READ | PROT_WRITE,
-			    PROT_READ | PROT_WRITE | PMAP_WIRED);
+			    PROT_READ | PROT_WRITE | PMAP_WIRED |
+			    PMAP_CANFAIL) != 0) {
+				pmap_remove(map->pmap, kva, loopva);
+
+				while ((pg = TAILQ_LAST(&pgldone, pglist))) {
+					TAILQ_REMOVE(&pgldone, pg, pageq);
+					TAILQ_INSERT_HEAD(&pgl, pg, pageq);
+					uvm_lock_pageq();
+					uvm_pageclean(pg);
+					uvm_unlock_pageq();
+				}
+
+				if (obj != NULL)
+					rw_exit(obj->vmobjlock);
+
+				uvm_unmap(map, kva, kva + size);
+				uvm_pglistfree(&pgl);
+
+				return 0;
+			}
 		}
 		loopva += PAGE_SIZE;
 		offset += PAGE_SIZE;


-- 
jca