From: Martin Pieuchot Subject: Towards killing uvm_km_kmemalloc_pla() To: tech@openbsd.org Date: Sun, 9 Nov 2025 22:44:51 +0000 14 years later, the conversion to km_alloc(9) is almost finished. Diff below removes all dead code from uvm_km_kmemalloc_pla() to ease reviews and make it simpler to discuss the final conversion. It includes: - No behavior change - Remove unused arguments - Use `kmem_map' directly - Kill UVM_KMF_* flags and use UVM_FLAG_TRYLOCK where necessary Once applied we can easily see the remaining differences with km_alloc(9) internal which will help finding a consensus for the next step. ok? Index: kern/kern_malloc.c =================================================================== RCS file: /cvs/src/sys/kern/kern_malloc.c,v diff -u -p -r1.155 kern_malloc.c --- kern/kern_malloc.c 12 Jun 2025 20:37:58 -0000 1.155 +++ kern/kern_malloc.c 9 Nov 2025 22:27:57 -0000 @@ -217,12 +217,9 @@ malloc(size_t size, int type, int flags) mtx_leave(&malloc_mtx); npg = atop(round_page(allocsize)); s = splvm(); - va = (caddr_t)uvm_km_kmemalloc_pla(kmem_map, NULL, - (vsize_t)ptoa(npg), 0, - ((flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0) | - ((flags & M_CANFAIL) ? UVM_KMF_CANFAIL : 0), - no_constraint.ucr_low, no_constraint.ucr_high, - 0, 0, 0); + va = (caddr_t)uvm_km_kmemalloc_pla((vsize_t)ptoa(npg), + (flags & (M_NOWAIT|M_CANFAIL)), + no_constraint.ucr_low, no_constraint.ucr_high); splx(s); if (va == NULL) { /* @@ -428,7 +425,7 @@ free(void *addr, int type, size_t freeds kup->ku_pagecnt = 0; mtx_leave(&malloc_mtx); s = splvm(); - uvm_km_free(kmem_map, (vaddr_t)addr, ptoa(pagecnt)); + uvm_km_free((vaddr_t)addr, ptoa(pagecnt)); splx(s); #ifdef KMEMSTATS mtx_enter(&malloc_mtx); Index: uvm/uvm_extern.h =================================================================== RCS file: /cvs/src/sys/uvm/uvm_extern.h,v diff -u -p -r1.185 uvm_extern.h --- uvm/uvm_extern.h 8 Nov 2025 17:23:22 -0000 1.185 +++ uvm/uvm_extern.h 9 Nov 2025 22:31:40 -0000 @@ -127,15 +127,6 @@ typedef int vm_prot_t; /* offset not known(obj) or don't care(!obj) */ /* - * the following defines are for uvm_km_kmemalloc's flags - */ -#define UVM_KMF_NOWAIT 0x1 /* matches M_NOWAIT */ -#define UVM_KMF_VALLOC 0x2 /* allocate VA only */ -#define UVM_KMF_CANFAIL 0x4 /* caller handles failure */ -#define UVM_KMF_ZERO 0x08 /* zero pages */ -#define UVM_KMF_TRYLOCK UVM_FLAG_TRYLOCK /* try locking only */ - -/* * flags for uvm_pagealloc() */ #define UVM_PGA_USERESERVE 0x0001 /* ok to use reserve pages */ @@ -286,12 +277,8 @@ int uvm_io(vm_map_t, struct uio *, int #define UVM_IO_FIXPROT 0x01 -void uvm_km_free(vm_map_t, vaddr_t, vsize_t); -vaddr_t uvm_km_kmemalloc_pla(struct vm_map *, - struct uvm_object *, vsize_t, vsize_t, int, - paddr_t, paddr_t, paddr_t, paddr_t, int); -#define uvm_km_kmemalloc(map, obj, sz, flags) \ - uvm_km_kmemalloc_pla(map, obj, sz, 0, flags, 0, (paddr_t)-1, 0, 0, 0) +void uvm_km_free(vaddr_t, vsize_t); +vaddr_t uvm_km_kmemalloc_pla(vsize_t, int, paddr_t, paddr_t); struct vm_map *uvm_km_suballoc(vm_map_t, vaddr_t *, vaddr_t *, vsize_t, int, boolean_t, vm_map_t); /* Index: uvm/uvm_km.c =================================================================== RCS file: /cvs/src/sys/uvm/uvm_km.c,v diff -u -p -r1.157 uvm_km.c --- uvm/uvm_km.c 14 Jul 2025 08:42:54 -0000 1.157 +++ uvm/uvm_km.c 9 Nov 2025 22:30:33 -0000 @@ -130,6 +130,7 @@ */ #include +#include #include #include #include @@ -314,111 +315,71 @@ uvm_km_pgremove_intrsafe(vaddr_t start, /* * uvm_km_kmemalloc: lower level kernel memory allocator for malloc() * - * => we map wired memory into the specified map using the obj passed in + * => we map wired memory into the kernel map * => NOTE: we can return NULL even if we can wait if there is not enough * free VM space in the map... caller should be prepared to handle * this case. * => we return KVA of memory allocated - * => flags: NOWAIT, VALLOC - just allocate VA, TRYLOCK - fail if we can't - * lock the map - * => low, high, alignment, boundary, nsegs are the corresponding parameters - * to uvm_pglistalloc + * => flags: M_NOWAIT, M_CANFAIL + * => low, high, are the corresponding parameters to uvm_pglistalloc * => flags: ZERO - correspond to uvm_pglistalloc flags */ vaddr_t -uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size, - vsize_t valign, int flags, paddr_t low, paddr_t high, paddr_t alignment, - paddr_t boundary, int nsegs) +uvm_km_kmemalloc_pla(vsize_t size, int flags, paddr_t low, paddr_t high) { vaddr_t kva, loopva; voff_t offset; struct vm_page *pg; struct pglist pgl; - int pla_flags; - - KASSERT(vm_map_pmap(map) == pmap_kernel()); - /* UVM_KMF_VALLOC => !UVM_KMF_ZERO */ - KASSERT(!(flags & UVM_KMF_VALLOC) || - !(flags & UVM_KMF_ZERO)); + int pla_flags = 0; /* setup for call */ size = round_page(size); - kva = vm_map_min(map); /* hint */ - if (nsegs == 0) - nsegs = atop(size); + kva = vm_map_min(kmem_map); /* hint */ /* allocate some virtual space */ - if (__predict_false(uvm_map(map, &kva, size, obj, UVM_UNKNOWN_OFFSET, - valign, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, - MAP_INHERIT_NONE, MADV_RANDOM, (flags & UVM_KMF_TRYLOCK))) != 0)) { + if (__predict_false(uvm_map(kmem_map, &kva, size, NULL, + UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, + MAP_INHERIT_NONE, MADV_RANDOM, 0)) != 0)) { return 0; } - /* if all we wanted was VA, return now */ - if (flags & UVM_KMF_VALLOC) { - return kva; - } - - /* recover object offset from virtual address */ - if (obj != NULL) - offset = kva - vm_map_min(kernel_map); - else - offset = 0; - /* * now allocate and map in the memory... note that we are the only ones * whom should ever get a handle on this area of VM. */ TAILQ_INIT(&pgl); - pla_flags = 0; KASSERT(uvmexp.swpgonly <= uvmexp.swpages); - if ((flags & UVM_KMF_NOWAIT) || - ((flags & UVM_KMF_CANFAIL) && + if ((flags & M_NOWAIT) || ((flags & M_CANFAIL) && uvmexp.swpages - uvmexp.swpgonly <= atop(size))) pla_flags |= UVM_PLA_NOWAIT; else pla_flags |= UVM_PLA_WAITOK; - if (flags & UVM_KMF_ZERO) - pla_flags |= UVM_PLA_ZERO; - if (uvm_pglistalloc(size, low, high, alignment, boundary, &pgl, nsegs, + if (uvm_pglistalloc(size, low, high, 0, 0, &pgl, atop(size), pla_flags) != 0) { /* Failed. */ - uvm_unmap(map, kva, kva + size); + uvm_unmap(kmem_map, kva, kva + size); return (0); } - if (obj != NULL) - rw_enter(obj->vmobjlock, RW_WRITE); - + offset = 0; loopva = kva; while (loopva != kva + size) { pg = TAILQ_FIRST(&pgl); TAILQ_REMOVE(&pgl, pg, pageq); - uvm_pagealloc_pg(pg, obj, offset, NULL); + uvm_pagealloc_pg(pg, NULL, offset, NULL); atomic_clearbits_int(&pg->pg_flags, PG_BUSY); UVM_PAGE_OWN(pg, NULL); - /* - * map it in: note that we call pmap_enter with the map and - * object unlocked in case we are kmem_map. - */ - if (obj == NULL) { - pmap_kenter_pa(loopva, VM_PAGE_TO_PHYS(pg), - PROT_READ | PROT_WRITE); - } else { - pmap_enter(map->pmap, loopva, VM_PAGE_TO_PHYS(pg), - PROT_READ | PROT_WRITE, - PROT_READ | PROT_WRITE | PMAP_WIRED); - } + pmap_kenter_pa(loopva, VM_PAGE_TO_PHYS(pg), + PROT_READ | PROT_WRITE); loopva += PAGE_SIZE; offset += PAGE_SIZE; } KASSERT(TAILQ_EMPTY(&pgl)); pmap_update(pmap_kernel()); - if (obj != NULL) - rw_exit(obj->vmobjlock); - return kva; } @@ -426,9 +387,9 @@ uvm_km_kmemalloc_pla(struct vm_map *map, * uvm_km_free: free an area of kernel memory */ void -uvm_km_free(struct vm_map *map, vaddr_t addr, vsize_t size) +uvm_km_free(vaddr_t addr, vsize_t size) { - uvm_unmap(map, trunc_page(addr), round_page(addr+size)); + uvm_unmap(kmem_map, trunc_page(addr), round_page(addr+size)); } #if defined(__HAVE_PMAP_DIRECT) @@ -505,7 +466,7 @@ uvm_km_page_init(void) NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_NONE, - MADV_RANDOM, UVM_KMF_TRYLOCK)) != 0) { + MADV_RANDOM, UVM_FLAG_TRYLOCK)) != 0) { bulk /= 2; continue; } @@ -568,12 +529,12 @@ uvm_km_thread(void *arg) /* * If there was nothing on the freelist, then we * must obtain at least one page to make progress. - * So, only use UVM_KMF_TRYLOCK for the first page + * So, only use UVM_FLAG_TRYLOCK for the first page * if fp != NULL */ flags = UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_NONE, - MADV_RANDOM, fp != NULL ? UVM_KMF_TRYLOCK : 0); + MADV_RANDOM, fp != NULL ? UVM_FLAG_TRYLOCK : 0); memset(pg, 0, sizeof(pg)); for (i = 0; i < nitems(pg); i++) { pg[i] = vm_map_min(kernel_map); @@ -586,7 +547,7 @@ uvm_km_thread(void *arg) /* made progress, so don't sleep for more */ flags = UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_NONE, - MADV_RANDOM, UVM_KMF_TRYLOCK); + MADV_RANDOM, UVM_FLAG_TRYLOCK); } mtx_enter(&uvm_km_pages.mtx); @@ -736,7 +697,7 @@ alloc_va: struct uvm_object *uobj = NULL; if (kd->kd_trylock) - mapflags |= UVM_KMF_TRYLOCK; + mapflags |= UVM_FLAG_TRYLOCK; if (kp->kp_object) uobj = *kp->kp_object;