Index: sys/amd64/amd64/pmap.c =================================================================== --- sys/amd64/amd64/pmap.c +++ sys/amd64/amd64/pmap.c @@ -2219,14 +2219,9 @@ static __inline void pmap_free_zero_pages(struct spglist *free) { - vm_page_t m; int count; - for (count = 0; (m = SLIST_FIRST(free)) != NULL; count++) { - SLIST_REMOVE_HEAD(free, plinks.s.ss); - /* Preserve the page's PG_ZERO setting. */ - vm_page_free_toq(m); - } + count = vm_page_free_spglist(free); atomic_subtract_int(&vm_cnt.v_wire_count, count); } Index: sys/arm/arm/pmap-v6.c =================================================================== --- sys/arm/arm/pmap-v6.c +++ sys/arm/arm/pmap-v6.c @@ -2544,18 +2544,6 @@ return (m); } -static __inline void -pmap_free_zero_pages(struct spglist *free) -{ - vm_page_t m; - - while ((m = SLIST_FIRST(free)) != NULL) { - SLIST_REMOVE_HEAD(free, plinks.s.ss); - /* Preserve the page's PG_ZERO setting. */ - vm_page_free_toq(m); - } -} - /* * Schedule the specified unused L2 page table page to be freed. Specifically, * add the page to the specified list of pages that will be released to the @@ -2941,7 +2929,7 @@ m_pc->wire_count = 1; atomic_add_int(&vm_cnt.v_wire_count, 1); } - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); return (m_pc); } @@ -3704,7 +3692,7 @@ VM_ALLOC_NORMAL | VM_ALLOC_WIRED)) == NULL) { SLIST_INIT(&free); pmap_remove_pte1(pmap, pte1p, pte1_trunc(va), &free); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); CTR3(KTR_PMAP, "%s: failure for va %#x in pmap %p", __func__, va, pmap); return (FALSE); @@ -4228,7 +4216,7 @@ sched_unpin(); rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -4302,7 +4290,7 @@ vm_page_aflag_clear(m, PGA_WRITEABLE); sched_unpin(); rw_wunlock(&pvh_global_lock); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -4489,7 +4477,7 @@ sched_unpin(); rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -4598,7 +4586,7 @@ SLIST_INIT(&free); if (pmap_unwire_pt2(pmap, va, mpt2pg, &free)) { pmap_tlb_flush(pmap, va); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } mpt2pg = NULL; @@ -6072,7 +6060,7 @@ if (pmap_unwire_pt2(dst_pmap, addr, dst_mpt2pg, &free)) { pmap_tlb_flush(dst_pmap, addr); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } goto out; } Index: sys/arm64/arm64/pmap.c =================================================================== --- sys/arm64/arm64/pmap.c +++ sys/arm64/arm64/pmap.c @@ -1260,18 +1260,6 @@ /*************************************************** * Page table page management routines..... ***************************************************/ -static __inline void -pmap_free_zero_pages(struct spglist *free) -{ - vm_page_t m; - - while ((m = SLIST_FIRST(free)) != NULL) { - SLIST_REMOVE_HEAD(free, plinks.s.ss); - /* Preserve the page's PG_ZERO setting. */ - vm_page_free_toq(m); - } -} - /* * Schedule the specified unused page table page to be freed. Specifically, * add the page to the specified list of pages that will be released to the @@ -1915,7 +1903,7 @@ m_pc->wire_count = 1; atomic_add_int(&vm_cnt.v_wire_count, 1); } - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); return (m_pc); } @@ -2423,7 +2411,7 @@ if (lock != NULL) rw_wunlock(lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -2528,7 +2516,7 @@ } vm_page_aflag_clear(m, PGA_WRITEABLE); rw_wunlock(lock); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -3214,7 +3202,7 @@ SLIST_INIT(&free); if (pmap_unwire_l3(pmap, va, mpte, &free)) { pmap_invalidate_page(pmap, va); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } mpte = NULL; } @@ -3728,7 +3716,7 @@ if (lock != NULL) rw_wunlock(lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -4189,7 +4177,7 @@ not_cleared < PMAP_TS_REFERENCED_MAX); out: rw_wunlock(lock); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); return (cleared + not_cleared); } Index: sys/i386/i386/pmap.c =================================================================== --- sys/i386/i386/pmap.c +++ sys/i386/i386/pmap.c @@ -1703,14 +1703,9 @@ static __inline void pmap_free_zero_pages(struct spglist *free) { - vm_page_t m; int count; - for (count = 0; (m = SLIST_FIRST(free)) != NULL; count++) { - SLIST_REMOVE_HEAD(free, plinks.s.ss); - /* Preserve the page's PG_ZERO setting. */ - vm_page_free_toq(m); - } + count = vm_page_free_spglist(free); atomic_subtract_int(&vm_cnt.v_wire_count, count); } Index: sys/riscv/riscv/pmap.c =================================================================== --- sys/riscv/riscv/pmap.c +++ sys/riscv/riscv/pmap.c @@ -1069,18 +1069,6 @@ /*************************************************** * Page table page management routines..... ***************************************************/ -static __inline void -pmap_free_zero_pages(struct spglist *free) -{ - vm_page_t m; - - while ((m = SLIST_FIRST(free)) != NULL) { - SLIST_REMOVE_HEAD(free, plinks.s.ss); - /* Preserve the page's PG_ZERO setting. */ - vm_page_free_toq(m); - } -} - /* * Schedule the specified unused page table page to be freed. Specifically, * add the page to the specified list of pages that will be released to the @@ -1883,7 +1871,7 @@ rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -1949,7 +1937,7 @@ } vm_page_aflag_clear(m, PGA_WRITEABLE); rw_wunlock(&pvh_global_lock); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -2384,7 +2372,7 @@ SLIST_INIT(&free); if (pmap_unwire_l3(pmap, va, mpte, &free)) { pmap_invalidate_page(pmap, va); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } mpte = NULL; } @@ -2790,7 +2778,7 @@ rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); } /* @@ -3092,7 +3080,7 @@ out: rw_wunlock(lock); rw_runlock(&pvh_global_lock); - pmap_free_zero_pages(&free); + vm_page_free_spglist(&free); return (cleared + not_cleared); } Index: sys/vm/vm_page.h =================================================================== --- sys/vm/vm_page.h +++ sys/vm/vm_page.h @@ -547,6 +547,7 @@ vm_page_bits_t vm_page_bits(int base, int size); void vm_page_zero_invalid(vm_page_t m, boolean_t setvalid); void vm_page_free_toq(vm_page_t m); +int vm_page_free_spglist(struct spglist *free); void vm_page_dirty_KBI(vm_page_t m); void vm_page_lock_KBI(vm_page_t m, const char *file, int line); Index: sys/vm/vm_page.c =================================================================== --- sys/vm/vm_page.c +++ sys/vm/vm_page.c @@ -2518,15 +2518,8 @@ } if (m_mtx != NULL) mtx_unlock(m_mtx); - if ((m = SLIST_FIRST(&free)) != NULL) { - mtx_lock(&vm_page_queue_free_mtx); - do { - SLIST_REMOVE_HEAD(&free, plinks.s.ss); - vm_page_free_phys(m); - } while ((m = SLIST_FIRST(&free)) != NULL); - vm_page_free_wakeup(); - mtx_unlock(&vm_page_queue_free_mtx); - } + if (!SLIST_EMPTY(&free)) + vm_page_free_spglist(&free); /* this calls vm_page_free_prep() unlike old code...*/ return (error); } @@ -3055,6 +3048,42 @@ } /* + * vm_page_free_spglist: + * + * Returns a list of pages to the free list, disassociating it + * from any VM object. In another word, this is equivalent to + * calling vm_page_free_toq() for each page of a list of VM objects. + * + * The objects must be locked. The pages must be locked if it is + * managed. + * + * Return value indicates the number of VM page objects freed. + */ +int +vm_page_free_spglist(struct spglist *free) +{ + vm_page_t m; + int count; + struct pglist pgl; + + if (SLIST_EMPTY(free)) + return (0); + + count = 0; + TAILQ_INIT(&pgl); + while ((m = SLIST_FIRST(free)) != NULL) + { + count++; + SLIST_REMOVE_HEAD(free, plinks.s.ss); + if (vm_page_free_prep(m, false)) + TAILQ_INSERT_TAIL(&pgl, m, listq); + } + if (!TAILQ_EMPTY(&pgl)) /* vm_page_free_phys_pglist() checks this; should I call here myself? */ + vm_page_free_phys_pglist(&pgl); + return (count); +} + +/* * vm_page_wire: * * Mark this page as wired down by yet