git: 6dd15b7a233a - main - vm_phys; fix uncalled free_contig

From: Doug Moore <dougm_at_FreeBSD.org>
Date: Thu, 21 Dec 2023 03:42:38 UTC
The branch main has been updated by dougm:

URL: https://cgit.FreeBSD.org/src/commit/?id=6dd15b7a233a87d0895cb6806ae13cfaf814b44c

commit 6dd15b7a233a87d0895cb6806ae13cfaf814b44c
Author:     Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2023-12-21 03:37:47 +0000
Commit:     Doug Moore <dougm@FreeBSD.org>
CommitDate: 2023-12-21 03:37:47 +0000

    vm_phys; fix uncalled free_contig
    
    Function vm_phys_free_contig does not always free memory properly when
    the npages parameter is less than max block size.  Change it so that it does.
    
    Note that this function is not currently invoked, and this error was
    not triggered in earlier versions of the code.
    
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D42891
---
 sys/vm/vm_phys.c | 38 ++++++++++++--------------------------
 1 file changed, 12 insertions(+), 26 deletions(-)

diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c
index cd75ed092691..8c15f107c2f9 100644
--- a/sys/vm/vm_phys.c
+++ b/sys/vm/vm_phys.c
@@ -1169,24 +1169,6 @@ vm_phys_free_pages(vm_page_t m, int order)
 	vm_freelist_add(fl, m, order, 1);
 }
 
-/*
- * Return the largest possible order of a set of pages starting at m.
- */
-static int
-max_order(vm_page_t m)
-{
-
-	/*
-	 * Unsigned "min" is used here so that "order" is assigned
-	 * "VM_NFREEORDER - 1" when "m"'s physical address is zero
-	 * or the low-order bits of its physical address are zero
-	 * because the size of a physical address exceeds the size of
-	 * a long.
-	 */
-	return (min(ffsll(VM_PAGE_TO_PHYS(m) >> PAGE_SHIFT) - 1,
-	    VM_NFREEORDER - 1));
-}
-
 /*
  * Free a contiguous, arbitrarily sized set of physical pages, without
  * merging across set boundaries.
@@ -1211,7 +1193,7 @@ vm_phys_enqueue_contig(vm_page_t m, u_long npages)
 	fl = (*seg->free_queues)[m->pool];
 	m_end = m + npages;
 	/* Free blocks of increasing size. */
-	lo = VM_PAGE_TO_PHYS(m) >> PAGE_SHIFT;
+	lo = atop(VM_PAGE_TO_PHYS(m));
 	if (m < m_end &&
 	    (diff = lo ^ (lo + npages - 1)) != 0) {
 		order = min(flsll(diff) - 1, VM_NFREEORDER - 1);
@@ -1239,18 +1221,22 @@ vm_phys_enqueue_contig(vm_page_t m, u_long npages)
 void
 vm_phys_free_contig(vm_page_t m, u_long npages)
 {
-	int order_start, order_end;
+	vm_paddr_t lo;
 	vm_page_t m_start, m_end;
+	unsigned max_order, order_start, order_end;
 
 	vm_domain_free_assert_locked(vm_pagequeue_domain(m));
 
+	lo = atop(VM_PAGE_TO_PHYS(m));
+	max_order = min(flsll(lo ^ (lo + npages)) - 1, VM_NFREEORDER - 1);
+
 	m_start = m;
-	order_start = max_order(m_start);
-	if (order_start < VM_NFREEORDER - 1)
+	order_start = ffsll(lo) - 1;
+	if (order_start < max_order)
 		m_start += 1 << order_start;
 	m_end = m + npages;
-	order_end = max_order(m_end);
-	if (order_end < VM_NFREEORDER - 1)
+	order_end = ffsll(lo + npages) - 1;
+	if (order_end < max_order)
 		m_end -= 1 << order_end;
 	/*
 	 * Avoid unnecessary coalescing by freeing the pages at the start and
@@ -1258,9 +1244,9 @@ vm_phys_free_contig(vm_page_t m, u_long npages)
 	 */
 	if (m_start < m_end)
 		vm_phys_enqueue_contig(m_start, m_end - m_start);
-	if (order_start < VM_NFREEORDER - 1)
+	if (order_start < max_order)
 		vm_phys_free_pages(m, order_start);
-	if (order_end < VM_NFREEORDER - 1)
+	if (order_end < max_order)
 		vm_phys_free_pages(m_end, order_end);
 }