On 30 Jan 2025, at 22:11, Ruslan Bukin <b...@freebsd.org> wrote: > > Hi Doug, > > riscv seems to panic after this commit. See the message > https://people.freebsd.org/~br/panic.txt > > I think I hit the same panic around a week ago with the previous (now > reverted) commit.
Does 4015ff43cbbe fix this for you? Jess > On Wed, Jan 29, 2025 at 09:14:38AM +0000, Doug Moore wrote: >> The branch main has been updated by dougm: >> >> URL: >> https://cgit.FreeBSD.org/src/commit/?id=0078df5f025854600595462e56fa95d34e732141 >> >> commit 0078df5f025854600595462e56fa95d34e732141 >> Author: Doug Moore <do...@freebsd.org> >> AuthorDate: 2025-01-29 09:13:17 +0000 >> Commit: Doug Moore <do...@freebsd.org> >> CommitDate: 2025-01-29 09:13:17 +0000 >> >> vm_phys: reduce touching of page->pool fields >> >> Change the usage of the pool field in vm_page structs. >> >> Currently, every page belongs to a pool, and the pool field identifies >> that pool, whether the page is allocated or free. >> >> With this change, the pool field of the first page of a free block is >> used by the buddy allocator to identify its pool, but the buddy >> allocator makes no guarantees about the pool field value for allocated >> pages. The buddy allocator requires that a pool parameter be passed as >> part of freeing memory. A function that allocates memory may use the >> pool field of a page to record what pool to pass as that parameter >> when the memory is freed, but might not need to do so for every >> allocated page. >> >> Suggested by: alc >> Reviewed by: markj (previous version) >> Tested by: pho >> Differential Revision: https://reviews.freebsd.org/D45409 >> --- >> sys/vm/vm_kern.c | 2 +- >> sys/vm/vm_page.c | 97 ++++++++++++++++++++++-------------------- >> sys/vm/vm_phys.c | 123 >> ++++++++++++++++++++++++++++------------------------- >> sys/vm/vm_phys.h | 6 +-- >> sys/vm/vm_reserv.c | 31 +++++++------- >> 5 files changed, 136 insertions(+), 123 deletions(-) >> >> diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c >> index 86ab2529e27f..2b85dbde1dd6 100644 >> --- a/sys/vm/vm_kern.c >> +++ b/sys/vm/vm_kern.c >> @@ -953,7 +953,7 @@ kmem_bootstrap_free(vm_offset_t start, vm_size_t size) >> >> vmd = vm_pagequeue_domain(m); >> vm_domain_free_lock(vmd); >> - vm_phys_free_pages(m, 0); >> + vm_phys_free_pages(m, m->pool, 0); >> vm_domain_free_unlock(vmd); >> >> vm_domain_freecnt_inc(vmd, 1); >> diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c >> index ba22c7f97f2f..961b32da6599 100644 >> --- a/sys/vm/vm_page.c >> +++ b/sys/vm/vm_page.c >> @@ -572,6 +572,7 @@ vm_page_startup(vm_offset_t vaddr) >> #if defined(__i386__) && defined(VM_PHYSSEG_DENSE) >> long ii; >> #endif >> + int pool; >> #ifdef VM_FREEPOOL_LAZYINIT >> int lazyinit; >> #endif >> @@ -651,6 +652,8 @@ vm_page_startup(vm_offset_t vaddr) >> dump_add_page(pa); >> pa += PAGE_SIZE; >> } >> +#else >> + (void)pa; >> #endif >> /* >> * Compute the number of pages of memory that will be available for >> @@ -755,9 +758,12 @@ vm_page_startup(vm_offset_t vaddr) >> */ >> vm_phys_init(); >> >> + pool = VM_FREEPOOL_DEFAULT; >> #ifdef VM_FREEPOOL_LAZYINIT >> lazyinit = 1; >> TUNABLE_INT_FETCH("debug.vm.lazy_page_init", &lazyinit); >> + if (lazyinit) >> + pool = VM_FREEPOOL_LAZYINIT; >> #endif >> >> /* >> @@ -777,48 +783,27 @@ vm_page_startup(vm_offset_t vaddr) >> seg = &vm_phys_segs[segind]; >> >> /* >> - * If lazy vm_page initialization is not enabled, simply >> - * initialize all of the pages in the segment. Otherwise, we >> - * only initialize: >> - * 1. Pages not covered by phys_avail[], since they might be >> - * freed to the allocator at some future point, e.g., by >> - * kmem_bootstrap_free(). >> - * 2. The first page of each run of free pages handed to the >> - * vm_phys allocator, which in turn defers initialization >> - * of pages until they are needed. >> - * This avoids blocking the boot process for long periods, which >> - * may be relevant for VMs (which ought to boot as quickly as >> - * possible) and/or systems with large amounts of physical >> - * memory. >> + * Initialize pages not covered by phys_avail[], since they >> + * might be freed to the allocator at some future point, e.g., >> + * by kmem_bootstrap_free(). >> */ >> -#ifdef VM_FREEPOOL_LAZYINIT >> - if (lazyinit) { >> - startp = seg->start; >> - for (i = 0; phys_avail[i + 1] != 0; i += 2) { >> - if (startp >= seg->end) >> - break; >> - >> - if (phys_avail[i + 1] < startp) >> - continue; >> - if (phys_avail[i] <= startp) { >> - startp = phys_avail[i + 1]; >> - continue; >> - } >> - >> - m = vm_phys_seg_paddr_to_vm_page(seg, startp); >> - for (endp = MIN(phys_avail[i], seg->end); >> - startp < endp; startp += PAGE_SIZE, m++) { >> - vm_page_init_page(m, startp, segind, >> - VM_FREEPOOL_DEFAULT); >> - } >> + startp = seg->start; >> + for (i = 0; phys_avail[i + 1] != 0; i += 2) { >> + if (startp >= seg->end) >> + break; >> + if (phys_avail[i + 1] < startp) >> + continue; >> + if (phys_avail[i] <= startp) { >> + startp = phys_avail[i + 1]; >> + continue; >> } >> - } else >> -#endif >> - for (m = seg->first_page, pa = seg->start; >> - pa < seg->end; m++, pa += PAGE_SIZE) { >> - vm_page_init_page(m, pa, segind, >> + m = vm_phys_seg_paddr_to_vm_page(seg, startp); >> + for (endp = MIN(phys_avail[i], seg->end); >> + startp < endp; startp += PAGE_SIZE, m++) { >> + vm_page_init_page(m, startp, segind, >> VM_FREEPOOL_DEFAULT); >> } >> + } >> >> /* >> * Add the segment's pages that are covered by one of >> @@ -835,16 +820,30 @@ vm_page_startup(vm_offset_t vaddr) >> if (pagecount == 0) >> continue; >> >> + /* >> + * If lazy vm_page initialization is not enabled, simply >> + * initialize all of the pages in the segment covered by >> + * phys_avail. Otherwise, initialize only the first >> + * page of each run of free pages handed to the vm_phys >> + * allocator, which in turn defers initialization of >> + * pages until they are needed. >> + * >> + * This avoids blocking the boot process for long >> + * periods, which may be relevant for VMs (which ought >> + * to boot as quickly as possible) and/or systems with >> + * large amounts of physical memory. >> + */ >> m = vm_phys_seg_paddr_to_vm_page(seg, startp); >> -#ifdef VM_FREEPOOL_LAZYINIT >> - if (lazyinit) { >> - vm_page_init_page(m, startp, segind, >> - VM_FREEPOOL_LAZYINIT); >> + vm_page_init_page(m, startp, segind, pool); >> + if (pool == VM_FREEPOOL_DEFAULT) { >> + for (int j = 1; j < pagecount; j++) { >> + vm_page_init_page(&m[j], >> + startp + ptoa(j), segind, pool); >> + } >> } >> -#endif >> vmd = VM_DOMAIN(seg->domain); >> vm_domain_free_lock(vmd); >> - vm_phys_enqueue_contig(m, pagecount); >> + vm_phys_enqueue_contig(m, pool, pagecount); >> vm_domain_free_unlock(vmd); >> vm_domain_freecnt_inc(vmd, pagecount); >> vm_cnt.v_page_count += (u_int)pagecount; >> @@ -2341,6 +2340,7 @@ found: >> m->flags = flags; >> m->a.flags = 0; >> m->oflags = (object->flags & OBJ_UNMANAGED) != 0 ? VPO_UNMANAGED : 0; >> + m->pool = VM_FREEPOOL_DEFAULT; >> if ((req & (VM_ALLOC_NOBUSY | VM_ALLOC_SBUSY)) == 0) >> m->busy_lock = VPB_CURTHREAD_EXCLUSIVE; >> else if ((req & VM_ALLOC_SBUSY) != 0) >> @@ -2558,6 +2558,7 @@ vm_page_alloc_contig_domain(vm_object_t object, >> vm_pindex_t pindex, int domain, >> m->ref_count = 1; >> m->a.act_count = 0; >> m->oflags = oflags; >> + m->pool = VM_FREEPOOL_DEFAULT; >> if (vm_page_iter_insert(&pages, m, object, pindex, mpred)) { >> if ((req & VM_ALLOC_WIRED) != 0) >> vm_wire_sub(npages); >> @@ -2655,6 +2656,7 @@ found: >> m->flags = (m->flags & PG_ZERO) | flags; >> m->a.flags = 0; >> m->oflags = VPO_UNMANAGED; >> + m->pool = VM_FREEPOOL_DIRECT; >> m->busy_lock = VPB_UNBUSIED; >> if ((req & VM_ALLOC_WIRED) != 0) { >> vm_wire_add(1); >> @@ -2803,6 +2805,7 @@ vm_page_alloc_noobj_contig_domain(int domain, int req, >> u_long npages, >> m->ref_count = 1; >> m->a.act_count = 0; >> m->oflags = VPO_UNMANAGED; >> + m->pool = VM_FREEPOOL_DIRECT; >> >> /* >> * Zero the page before updating any mappings since the page is >> @@ -2881,7 +2884,7 @@ vm_page_zone_release(void *arg, void **store, int cnt) >> vm_domain_free_lock(vmd); >> for (i = 0; i < cnt; i++) { >> m = (vm_page_t)store[i]; >> - vm_phys_free_pages(m, 0); >> + vm_phys_free_pages(m, pgcache->pool, 0); >> } >> vm_domain_free_unlock(vmd); >> vm_domain_freecnt_inc(vmd, cnt); >> @@ -3266,7 +3269,7 @@ unlock: >> do { >> MPASS(vm_page_domain(m) == domain); >> SLIST_REMOVE_HEAD(&free, plinks.s.ss); >> - vm_phys_free_pages(m, 0); >> + vm_phys_free_pages(m, m->pool, 0); >> cnt++; >> } while ((m = SLIST_FIRST(&free)) != NULL); >> vm_domain_free_unlock(vmd); >> @@ -4271,7 +4274,7 @@ vm_page_free_toq(vm_page_t m) >> return; >> } >> vm_domain_free_lock(vmd); >> - vm_phys_free_pages(m, 0); >> + vm_phys_free_pages(m, m->pool, 0); >> vm_domain_free_unlock(vmd); >> vm_domain_freecnt_inc(vmd, 1); >> } >> diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c >> index cf1ed5818b2f..0b7de1d34255 100644 >> --- a/sys/vm/vm_phys.c >> +++ b/sys/vm/vm_phys.c >> @@ -187,7 +187,7 @@ SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD, >> static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int >> domain); >> static void vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end); >> static void vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist >> *fl, >> - int order, int tail); >> + int order, int pool, int tail); >> >> static bool __diagused >> vm_phys_pool_valid(int pool) >> @@ -391,10 +391,12 @@ sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS) >> #endif >> >> static void >> -vm_freelist_add(struct vm_freelist *fl, vm_page_t m, int order, int tail) >> +vm_freelist_add(struct vm_freelist *fl, vm_page_t m, int order, int pool, >> + int tail) >> { >> >> m->order = order; >> + m->pool = pool; >> if (tail) >> TAILQ_INSERT_TAIL(&fl[order].pl, m, listq); >> else >> @@ -687,7 +689,7 @@ vm_phys_register_domains(int ndomains __numa_used, >> */ >> static __inline void >> vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist *fl, int order, >> - int tail) >> + int pool, int tail) >> { >> vm_page_t m_buddy; >> >> @@ -697,19 +699,20 @@ vm_phys_split_pages(vm_page_t m, int oind, struct >> vm_freelist *fl, int order, >> KASSERT(m_buddy->order == VM_NFREEORDER, >> ("vm_phys_split_pages: page %p has unexpected order %d", >> m_buddy, m_buddy->order)); >> - vm_freelist_add(fl, m_buddy, oind, tail); >> + vm_freelist_add(fl, m_buddy, oind, pool, tail); >> } >> } >> >> static void >> -vm_phys_enq_chunk(struct vm_freelist *fl, vm_page_t m, int order, int tail) >> +vm_phys_enq_chunk(struct vm_freelist *fl, vm_page_t m, int order, int pool, >> + int tail) >> { >> KASSERT(order >= 0 && order < VM_NFREEORDER, >> ("%s: invalid order %d", __func__, order)); >> >> - vm_freelist_add(fl, m, order, tail); >> + vm_freelist_add(fl, m, order, pool, tail); >> #ifdef VM_FREEPOOL_LAZYINIT >> - if (__predict_false(m->pool == VM_FREEPOOL_LAZYINIT)) { >> + if (__predict_false(pool == VM_FREEPOOL_LAZYINIT)) { >> vm_page_t m_next; >> vm_paddr_t pa; >> int npages; >> @@ -738,7 +741,8 @@ vm_phys_enq_chunk(struct vm_freelist *fl, vm_page_t m, >> int order, int tail) >> * The physical page m's buddy must not be free. >> */ >> static void >> -vm_phys_enq_beg(vm_page_t m, u_int npages, struct vm_freelist *fl, int tail) >> +vm_phys_enq_beg(vm_page_t m, u_int npages, struct vm_freelist *fl, int pool, >> + int tail) >> { >> int order; >> >> @@ -754,7 +758,7 @@ vm_phys_enq_beg(vm_page_t m, u_int npages, struct >> vm_freelist *fl, int tail) >> order = ilog2(npages); >> KASSERT(order < VM_NFREEORDER, >> ("%s: order %d is out of range", __func__, order)); >> - vm_phys_enq_chunk(fl, m, order, tail); >> + vm_phys_enq_chunk(fl, m, order, pool, tail); >> m += 1 << order; >> npages -= 1 << order; >> } >> @@ -774,7 +778,8 @@ vm_phys_enq_beg(vm_page_t m, u_int npages, struct >> vm_freelist *fl, int tail) >> * parameter m. Otherwise, the physical page m's buddy must not be free. >> */ >> static vm_page_t >> -vm_phys_enq_range(vm_page_t m, u_int npages, struct vm_freelist *fl, int >> tail) >> +vm_phys_enq_range(vm_page_t m, u_int npages, struct vm_freelist *fl, int >> pool, >> + int tail) >> { >> int order; >> >> @@ -788,7 +793,7 @@ vm_phys_enq_range(vm_page_t m, u_int npages, struct >> vm_freelist *fl, int tail) >> ("vm_phys_enq_range: page %p has unexpected order %d", >> m, m->order)); >> order = ffs(npages) - 1; >> - vm_phys_enq_chunk(fl, m, order, tail); >> + vm_phys_enq_chunk(fl, m, order, pool, tail); >> m += 1 << order; >> npages -= 1 << order; >> } >> @@ -796,33 +801,30 @@ vm_phys_enq_range(vm_page_t m, u_int npages, struct >> vm_freelist *fl, int tail) >> } >> >> /* >> - * Set the pool for a contiguous, power of two-sized set of physical pages. >> + * Complete initialization a contiguous, power of two-sized set of physical >> + * pages. >> * >> * If the pages currently belong to the lazy init pool, then the >> corresponding >> * page structures must be initialized. In this case it is assumed that the >> * first page in the run has already been initialized. >> */ >> static void >> -vm_phys_set_pool(int pool, vm_page_t m, int order) >> +vm_phys_finish_init(vm_page_t m, int order) >> { >> #ifdef VM_FREEPOOL_LAZYINIT >> if (__predict_false(m->pool == VM_FREEPOOL_LAZYINIT)) { >> vm_paddr_t pa; >> int segind; >> >> - m->pool = pool; >> - >> TSENTER(); >> pa = m->phys_addr + PAGE_SIZE; >> segind = m->segind; >> for (vm_page_t m_tmp = m + 1; m_tmp < &m[1 << order]; >> m_tmp++, pa += PAGE_SIZE) >> - vm_page_init_page(m_tmp, pa, segind, pool); >> + vm_page_init_page(m_tmp, pa, segind, VM_NFREEPOOL); >> TSEXIT(); >> - } else >> + } >> #endif >> - for (vm_page_t m_tmp = m; m_tmp < &m[1 << order]; m_tmp++) >> - m_tmp->pool = pool; >> } >> >> /* >> @@ -833,7 +835,8 @@ vm_phys_set_pool(int pool, vm_page_t m, int order) >> * The returned pages may not be physically contiguous. However, in contrast >> * to performing multiple, back-to-back calls to vm_phys_alloc_pages(..., 0), >> * calling this function once to allocate the desired number of pages will >> - * avoid wasted time in vm_phys_split_pages(). >> + * avoid wasted time in vm_phys_split_pages(). The allocated pages have no >> + * valid pool field set. >> * >> * The free page queues for the specified domain must be locked. >> */ >> @@ -869,7 +872,8 @@ vm_phys_alloc_npages(int domain, int pool, int npages, >> vm_page_t ma[]) >> * Return excess pages to fl. Its order >> * [0, oind) queues are empty. >> */ >> - vm_phys_enq_range(m, avail - i, fl, 1); >> + vm_phys_enq_range(m, avail - i, fl, >> + pool, 1); >> return (npages); >> } >> } >> @@ -881,7 +885,7 @@ vm_phys_alloc_npages(int domain, int pool, int npages, >> vm_page_t ma[]) >> while ((m = TAILQ_FIRST(&alt[oind].pl)) != >> NULL) { >> vm_freelist_rem(alt, m, oind); >> - vm_phys_set_pool(pool, m, oind); >> + vm_phys_finish_init(m, oind); >> avail = i + (1 << oind); >> end = imin(npages, avail); >> while (i < end) >> @@ -893,7 +897,7 @@ vm_phys_alloc_npages(int domain, int pool, int npages, >> vm_page_t ma[]) >> * are empty. >> */ >> vm_phys_enq_range(m, avail - i, >> - fl, 1); >> + fl, pool, 1); >> return (npages); >> } >> } >> @@ -940,7 +944,7 @@ vm_phys_alloc_freelist_pages(int domain, int freelist, >> int pool, int order) >> if (m != NULL) { >> vm_freelist_rem(fl, m, oind); >> /* The order [order, oind) queues are empty. */ >> - vm_phys_split_pages(m, oind, fl, order, 1); >> + vm_phys_split_pages(m, oind, fl, order, pool, 1); >> return (m); >> } >> } >> @@ -957,9 +961,9 @@ vm_phys_alloc_freelist_pages(int domain, int freelist, >> int pool, int order) >> m = TAILQ_FIRST(&alt[oind].pl); >> if (m != NULL) { >> vm_freelist_rem(alt, m, oind); >> - vm_phys_set_pool(pool, m, oind); >> + vm_phys_finish_init(m, oind); >> /* The order [order, oind) queues are empty. */ >> - vm_phys_split_pages(m, oind, fl, order, 1); >> + vm_phys_split_pages(m, oind, fl, order, pool, 1); >> return (m); >> } >> } >> @@ -1198,11 +1202,12 @@ vm_phys_fictitious_unreg_range(vm_paddr_t start, >> vm_paddr_t end) >> >> /* >> * Free a contiguous, power of two-sized set of physical pages. >> + * The pool field in the first page determines the destination pool. >> * >> * The free page queues must be locked. >> */ >> void >> -vm_phys_free_pages(vm_page_t m, int order) >> +vm_phys_free_pages(vm_page_t m, int pool, int order) >> { >> struct vm_freelist *fl; >> struct vm_phys_seg *seg; >> @@ -1210,13 +1215,12 @@ vm_phys_free_pages(vm_page_t m, int order) >> vm_page_t m_buddy; >> >> KASSERT(m->order == VM_NFREEORDER, >> - ("vm_phys_free_pages: page %p has unexpected order %d", >> - m, m->order)); >> - KASSERT(vm_phys_pool_valid(m->pool), >> - ("vm_phys_free_pages: page %p has unexpected pool %d", >> - m, m->pool)); >> + ("%s: page %p has unexpected order %d", >> + __func__, m, m->order)); >> + KASSERT(vm_phys_pool_valid(pool), >> + ("%s: unexpected pool param %d", __func__, pool)); >> KASSERT(order < VM_NFREEORDER, >> - ("vm_phys_free_pages: order %d is out of range", order)); >> + ("%s: order %d is out of range", __func__, order)); >> seg = &vm_phys_segs[m->segind]; >> vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); >> if (order < VM_NFREEORDER - 1) { >> @@ -1230,15 +1234,14 @@ vm_phys_free_pages(vm_page_t m, int order) >> break; >> fl = (*seg->free_queues)[m_buddy->pool]; >> vm_freelist_rem(fl, m_buddy, order); >> - if (m_buddy->pool != m->pool) >> - vm_phys_set_pool(m->pool, m_buddy, order); >> + vm_phys_finish_init(m_buddy, order); >> order++; >> pa &= ~(((vm_paddr_t)1 << (PAGE_SHIFT + order)) - 1); >> m = vm_phys_seg_paddr_to_vm_page(seg, pa); >> } while (order < VM_NFREEORDER - 1); >> } >> - fl = (*seg->free_queues)[m->pool]; >> - vm_freelist_add(fl, m, order, 1); >> + fl = (*seg->free_queues)[pool]; >> + vm_freelist_add(fl, m, order, pool, 1); >> } >> >> #ifdef VM_FREEPOOL_LAZYINIT >> @@ -1290,12 +1293,13 @@ vm_phys_lazy_init_domain(int domain, bool locked) >> VM_ALLOC_NORMAL, 1 << oind); >> if (unlocked) >> vm_domain_free_unlock(vmd); >> - vm_phys_set_pool(VM_FREEPOOL_DEFAULT, m, oind); >> + vm_phys_finish_init(m, oind); >> if (unlocked) { >> vm_domain_freecnt_inc(vmd, 1 << oind); >> vm_domain_free_lock(vmd); >> } >> - vm_phys_free_pages(m, oind); >> + vm_phys_free_pages(m, VM_FREEPOOL_DEFAULT, >> + oind); >> } >> } >> } >> @@ -1344,12 +1348,12 @@ SYSINIT(vm_phys_lazy_init, SI_SUB_SMP, SI_ORDER_ANY, >> vm_phys_lazy_sysinit, >> >> /* >> * Free a contiguous, arbitrarily sized set of physical pages, without >> - * merging across set boundaries. >> + * merging across set boundaries. Assumes no pages have a valid pool field. >> * >> * The free page queues must be locked. >> */ >> void >> -vm_phys_enqueue_contig(vm_page_t m, u_long npages) >> +vm_phys_enqueue_contig(vm_page_t m, int pool, u_long npages) >> { >> struct vm_freelist *fl; >> struct vm_phys_seg *seg; >> @@ -1363,14 +1367,15 @@ vm_phys_enqueue_contig(vm_page_t m, u_long npages) >> */ >> vm_domain_free_assert_locked(vm_pagequeue_domain(m)); >> seg = &vm_phys_segs[m->segind]; >> - fl = (*seg->free_queues)[m->pool]; >> + fl = (*seg->free_queues)[pool]; >> m_end = m + npages; >> /* Free blocks of increasing size. */ >> lo = atop(VM_PAGE_TO_PHYS(m)); >> if (m < m_end && >> (diff = lo ^ (lo + npages - 1)) != 0) { >> order = min(ilog2(diff), VM_NFREEORDER - 1); >> - m = vm_phys_enq_range(m, roundup2(lo, 1 << order) - lo, fl, 1); >> + m = vm_phys_enq_range(m, roundup2(lo, 1 << order) - lo, fl, >> + pool, 1); >> } >> >> /* Free blocks of maximum size. */ >> @@ -1379,20 +1384,22 @@ vm_phys_enqueue_contig(vm_page_t m, u_long npages) >> KASSERT(seg == &vm_phys_segs[m->segind], >> ("%s: page range [%p,%p) spans multiple segments", >> __func__, m_end - npages, m)); >> - vm_phys_enq_chunk(fl, m, order, 1); >> + vm_phys_enq_chunk(fl, m, order, pool, 1); >> m += 1 << order; >> } >> /* Free blocks of diminishing size. */ >> - vm_phys_enq_beg(m, m_end - m, fl, 1); >> + vm_phys_enq_beg(m, m_end - m, fl, pool, 1); >> } >> >> /* >> * Free a contiguous, arbitrarily sized set of physical pages. >> + * Assumes that every page but the first has no valid pool field. >> + * Uses the pool value in the first page if valid, otherwise default. >> * >> * The free page queues must be locked. >> */ >> void >> -vm_phys_free_contig(vm_page_t m, u_long npages) >> +vm_phys_free_contig(vm_page_t m, int pool, u_long npages) >> { >> vm_paddr_t lo; >> vm_page_t m_start, m_end; >> @@ -1416,11 +1423,11 @@ vm_phys_free_contig(vm_page_t m, u_long npages) >> * end of the range last. >> */ >> if (m_start < m_end) >> - vm_phys_enqueue_contig(m_start, m_end - m_start); >> + vm_phys_enqueue_contig(m_start, pool, m_end - m_start); >> if (order_start < max_order) >> - vm_phys_free_pages(m, order_start); >> + vm_phys_free_pages(m, pool, order_start); >> if (order_end < max_order) >> - vm_phys_free_pages(m_end, order_end); >> + vm_phys_free_pages(m_end, pool, order_end); >> } >> >> /* >> @@ -1474,15 +1481,15 @@ vm_phys_unfree_page(vm_paddr_t pa) >> struct vm_phys_seg *seg; >> vm_paddr_t pa_half; >> vm_page_t m, m_set, m_tmp; >> - int order; >> + int order, pool; >> >> seg = vm_phys_paddr_to_seg(pa); >> vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); >> >> +#ifdef VM_FREEPOOL_LAZYINIT >> /* >> * The pages on the free lists must be initialized. >> */ >> -#ifdef VM_FREEPOOL_LAZYINIT >> vm_phys_lazy_init_domain(seg->domain, true); >> #endif >> >> @@ -1515,7 +1522,8 @@ vm_phys_unfree_page(vm_paddr_t pa) >> * is larger than a page, shrink "m_set" by returning the half >> * of "m_set" that does not contain "m" to the free lists. >> */ >> - fl = (*seg->free_queues)[m_set->pool]; >> + pool = m_set->pool; >> + fl = (*seg->free_queues)[pool]; >> order = m_set->order; >> vm_freelist_rem(fl, m_set, order); >> while (order > 0) { >> @@ -1527,7 +1535,7 @@ vm_phys_unfree_page(vm_paddr_t pa) >> m_tmp = m_set; >> m_set = vm_phys_seg_paddr_to_vm_page(seg, pa_half); >> } >> - vm_freelist_add(fl, m_tmp, order, 0); >> + vm_freelist_add(fl, m_tmp, order, pool, 0); >> } >> KASSERT(m_set == m, ("vm_phys_unfree_page: fatal inconsistency")); >> return (true); >> @@ -1668,7 +1676,8 @@ vm_phys_find_queues_contig( >> * alignment of the first physical page in the set. If the given value >> * "boundary" is non-zero, then the set of physical pages cannot cross >> * any physical address boundary that is a multiple of that value. Both >> - * "alignment" and "boundary" must be a power of two. >> + * "alignment" and "boundary" must be a power of two. Sets the pool >> + * field to DEFAULT in the first allocated page. >> */ >> vm_page_t >> vm_phys_alloc_contig(int domain, u_long npages, vm_paddr_t low, vm_paddr_t >> high, >> @@ -1727,12 +1736,12 @@ vm_phys_alloc_contig(int domain, u_long npages, >> vm_paddr_t low, vm_paddr_t high, >> fl = (*queues)[m->pool]; >> oind = m->order; >> vm_freelist_rem(fl, m, oind); >> - if (m->pool != VM_FREEPOOL_DEFAULT) >> - vm_phys_set_pool(VM_FREEPOOL_DEFAULT, m, oind); >> + vm_phys_finish_init(m, oind); >> } >> /* Return excess pages to the free lists. */ >> fl = (*queues)[VM_FREEPOOL_DEFAULT]; >> - vm_phys_enq_range(&m_run[npages], m - &m_run[npages], fl, 0); >> + vm_phys_enq_range(&m_run[npages], m - &m_run[npages], fl, >> + VM_FREEPOOL_DEFAULT, 0); >> >> /* Return page verified to satisfy conditions of request. */ >> pa_start = VM_PAGE_TO_PHYS(m_run); >> diff --git a/sys/vm/vm_phys.h b/sys/vm/vm_phys.h >> index 43d94a9420f2..046fe26b476d 100644 >> --- a/sys/vm/vm_phys.h >> +++ b/sys/vm/vm_phys.h >> @@ -64,15 +64,15 @@ vm_page_t vm_phys_alloc_contig(int domain, u_long >> npages, vm_paddr_t low, >> int vm_phys_alloc_npages(int domain, int pool, int npages, vm_page_t ma[]); >> vm_page_t vm_phys_alloc_pages(int domain, int pool, int order); >> int vm_phys_domain_match(int prefer, vm_paddr_t low, vm_paddr_t high); >> -void vm_phys_enqueue_contig(vm_page_t m, u_long npages); >> +void vm_phys_enqueue_contig(vm_page_t m, int pool, u_long npages); >> int vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end, >> vm_memattr_t memattr); >> void vm_phys_fictitious_unreg_range(vm_paddr_t start, vm_paddr_t end); >> vm_page_t vm_phys_fictitious_to_vm_page(vm_paddr_t pa); >> int vm_phys_find_range(vm_page_t bounds[], int segind, int domain, >> u_long npages, vm_paddr_t low, vm_paddr_t high); >> -void vm_phys_free_contig(vm_page_t m, u_long npages); >> -void vm_phys_free_pages(vm_page_t m, int order); >> +void vm_phys_free_contig(vm_page_t m, int pool, u_long npages); >> +void vm_phys_free_pages(vm_page_t m, int pool, int order); >> void vm_phys_init(void); >> vm_page_t vm_phys_paddr_to_vm_page(vm_paddr_t pa); >> vm_page_t vm_phys_seg_paddr_to_vm_page(struct vm_phys_seg *seg, vm_paddr_t >> pa); >> diff --git a/sys/vm/vm_reserv.c b/sys/vm/vm_reserv.c >> index ad513962d50d..04453e050a38 100644 >> --- a/sys/vm/vm_reserv.c >> +++ b/sys/vm/vm_reserv.c >> @@ -480,7 +480,7 @@ vm_reserv_depopulate(vm_reserv_t rv, int index) >> if (rv->popcnt == 0) { >> vm_reserv_remove(rv); >> vm_domain_free_lock(vmd); >> - vm_phys_free_pages(rv->pages, VM_LEVEL_0_ORDER); >> + vm_phys_free_pages(rv->pages, rv->pages->pool, VM_LEVEL_0_ORDER); >> vm_domain_free_unlock(vmd); >> counter_u64_add(vm_reserv_freed, 1); >> } >> @@ -943,7 +943,7 @@ static void >> vm_reserv_break(vm_reserv_t rv) >> { >> vm_page_t m; >> - int hi, lo, pos; >> + int pos, pos0, pos1; >> >> vm_reserv_assert_locked(rv); >> CTR5(KTR_VM, "%s: rv %p object %p popcnt %d inpartpop %d", >> @@ -954,23 +954,24 @@ vm_reserv_break(vm_reserv_t rv) >> for (; m < rv->pages + VM_LEVEL_0_NPAGES; m += VM_SUBLEVEL_0_NPAGES) >> #endif >> m->psind = 0; >> - hi = lo = -1; >> - pos = 0; >> - for (;;) { >> - bit_ff_at(rv->popmap, pos, VM_LEVEL_0_NPAGES, lo != hi, &pos); >> - if (lo == hi) { >> - if (pos == -1) >> - break; >> - lo = pos; >> - continue; >> - } >> + pos0 = bit_test(rv->popmap, 0) ? -1 : 0; >> + pos1 = -1 - pos0; >> + for (pos = 0; pos < VM_LEVEL_0_NPAGES; ) { >> + /* Find the first different bit after pos. */ >> + bit_ff_at(rv->popmap, pos + 1, VM_LEVEL_0_NPAGES, >> + pos1 < pos0, &pos); >> if (pos == -1) >> pos = VM_LEVEL_0_NPAGES; >> - hi = pos; >> + if (pos0 < pos1) { >> + pos0 = pos; >> + continue; >> + } >> + /* Free unused pages from pos0 to pos. */ >> + pos1 = pos; >> vm_domain_free_lock(VM_DOMAIN(rv->domain)); >> - vm_phys_enqueue_contig(&rv->pages[lo], hi - lo); >> + vm_phys_enqueue_contig(&rv->pages[pos0], VM_FREEPOOL_DEFAULT, >> + pos1 - pos0); >> vm_domain_free_unlock(VM_DOMAIN(rv->domain)); >> - lo = hi; >> } >> bit_nclear(rv->popmap, 0, VM_LEVEL_0_NPAGES - 1); >> rv->popcnt = 0; > Jess