git: b68c7ebf5e63 - main - vm_reserv: extract common gap-checking code

From: Doug Moore <dougm_at_FreeBSD.org>
Date: Mon, 31 Mar 2025 04:02:16 UTC
The branch main has been updated by dougm:

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

commit b68c7ebf5e633549dfda1cfa25991b097dfbcdce
Author:     Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2025-03-31 04:00:53 +0000
Commit:     Doug Moore <dougm@FreeBSD.org>
CommitDate: 2025-03-31 04:00:53 +0000

    vm_reserv: extract common gap-checking code
    
    vm_reserv_alloc_contig and vm_reserv_alloc_page both have code to
    determine whether a new reservation will fit between the predecessor
    and successor. Extract this code into a separate function rather than
    having it appear twice. Optimize slightly to avoid checking object
    size limit when there is a successor, and to avoid checking the upper
    bound at all when the size to be allocated is a multiple of
    reservation size.
    
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D49460
---
 sys/vm/vm_reserv.c | 175 ++++++++++++++++++++++++-----------------------------
 1 file changed, 80 insertions(+), 95 deletions(-)

diff --git a/sys/vm/vm_reserv.c b/sys/vm/vm_reserv.c
index 3dc278851cc9..e553d115a6d4 100644
--- a/sys/vm/vm_reserv.c
+++ b/sys/vm/vm_reserv.c
@@ -549,6 +549,73 @@ vm_reserv_has_pindex(vm_reserv_t rv, vm_pindex_t pindex)
 	return (((pindex - rv->pindex) & ~(VM_LEVEL_0_NPAGES - 1)) == 0);
 }
 
+/*
+ * How many pages should be in a new allocation that starts at the first page of
+ * the reservation superpage that contains 'first', fits between the allocations
+ * that include 'mpred' and 'msucc', fits within 'object', includes at least
+ * 'minpages' pages, and tries to include every allocated page in a superpage?
+ *
+ * We must synchronize with the reserv object lock to protect the pindex/object
+ * of the resulting reservations against rename while we are inspecting.
+ */
+static u_long
+vm_reserv_num_alloc_pages(vm_object_t object, vm_pindex_t first,
+    u_long minpages, vm_page_t mpred, vm_page_t msucc)
+{
+	vm_pindex_t leftcap, rightcap;
+	vm_reserv_t rv;
+	u_int allocpages;
+
+	allocpages = roundup2(minpages, VM_LEVEL_0_NPAGES);
+
+	vm_reserv_object_lock(object);
+	if (mpred != NULL) {
+		if ((rv = vm_reserv_from_page(mpred))->object != object)
+			leftcap = mpred->pindex + 1;
+		else
+			leftcap = rv->pindex + VM_LEVEL_0_NPAGES;
+		if (leftcap > first)
+			allocpages = 0;
+	}
+	if (minpages < allocpages) {
+		if (msucc == NULL) {
+			/*
+			 * Would the last new reservation extend past the end of
+			 * the object?
+			 *
+			 * If the object is unlikely to grow don't allocate a
+			 * reservation for the tail.
+			 */
+			if ((object->flags & OBJ_ANON) == 0)
+				rightcap = object->size;
+			else
+				rightcap = OBJ_MAX_SIZE;
+		} else {
+			/*
+			 * Would the last new reservation extend past the start
+			 * of another page or reservation?
+			 *
+			 * If the object would, don't allocate a reservation for
+			 * the tail.
+			 */
+			if ((rv = vm_reserv_from_page(msucc))->object != object)
+				rightcap = msucc->pindex;
+			else
+				rightcap = rv->pindex;
+		}
+		if (first + allocpages > rightcap) {
+			/*
+			 * A reservation for the last of the requested pages
+			 * will not fit.  Reduce the size of the upcoming
+			 * allocation accordingly.
+			 */
+			allocpages = minpages;
+		}
+	}
+	vm_reserv_object_unlock(object);
+	return (allocpages);
+}
+
 /*
  * Increases the given reservation's population count.  Moves the reservation
  * to the tail of the partially populated reservation queue.
@@ -623,9 +690,9 @@ vm_reserv_alloc_contig(vm_object_t object, vm_pindex_t pindex, int domain,
 	struct vm_domain *vmd;
 	vm_paddr_t pa, size;
 	vm_page_t m, m_ret, msucc;
-	vm_pindex_t first, leftcap, rightcap;
+	vm_pindex_t first;
 	vm_reserv_t rv;
-	u_long allocpages, maxpages, minpages;
+	u_long allocpages;
 	int i, index, n;
 
 	VM_OBJECT_ASSERT_WLOCKED(object);
@@ -690,63 +757,14 @@ out:
 	}
 
 	/*
-	 * Could at least one reservation fit between the first index to the
-	 * left that can be used ("leftcap") and the first index to the right
-	 * that cannot be used ("rightcap")?
-	 *
-	 * We must synchronize with the reserv object lock to protect the
-	 * pindex/object of the resulting reservations against rename while
-	 * we are inspecting.
+	 * Check whether an allocation including at least one reservation can
+	 * fit between mpred and msucc.
 	 */
 	first = pindex - VM_RESERV_INDEX(object, pindex);
-	minpages = VM_RESERV_INDEX(object, pindex) + npages;
-	maxpages = roundup2(minpages, VM_LEVEL_0_NPAGES);
-	allocpages = maxpages;
-	vm_reserv_object_lock(object);
-	if (mpred != NULL) {
-		if ((rv = vm_reserv_from_page(mpred))->object != object)
-			leftcap = mpred->pindex + 1;
-		else
-			leftcap = rv->pindex + VM_LEVEL_0_NPAGES;
-		if (leftcap > first) {
-			vm_reserv_object_unlock(object);
-			return (NULL);
-		}
-	}
-	if (msucc != NULL) {
-		if ((rv = vm_reserv_from_page(msucc))->object != object)
-			rightcap = msucc->pindex;
-		else
-			rightcap = rv->pindex;
-		if (first + maxpages > rightcap) {
-			if (maxpages == VM_LEVEL_0_NPAGES) {
-				vm_reserv_object_unlock(object);
-				return (NULL);
-			}
-
-			/*
-			 * At least one reservation will fit between "leftcap"
-			 * and "rightcap".  However, a reservation for the
-			 * last of the requested pages will not fit.  Reduce
-			 * the size of the upcoming allocation accordingly.
-			 */
-			allocpages = minpages;
-		}
-	}
-	vm_reserv_object_unlock(object);
-
-	/*
-	 * Would the last new reservation extend past the end of the object?
-	 *
-	 * If the object is unlikely to grow don't allocate a reservation for
-	 * the tail.
-	 */
-	if ((object->flags & OBJ_ANON) == 0 &&
-	    first + maxpages > object->size) {
-		if (maxpages == VM_LEVEL_0_NPAGES)
-			return (NULL);
-		allocpages = minpages;
-	}
+	allocpages = vm_reserv_num_alloc_pages(object, first,
+	    VM_RESERV_INDEX(object, pindex) + npages, mpred, msucc);
+	if (allocpages < VM_LEVEL_0_NPAGES)
+		return (NULL);
 
 	/*
 	 * Allocate the physical pages.  The alignment and boundary specified
@@ -817,7 +835,7 @@ vm_reserv_alloc_page(vm_object_t object, vm_pindex_t pindex, int domain,
 {
 	struct vm_domain *vmd;
 	vm_page_t m, msucc;
-	vm_pindex_t first, leftcap, rightcap;
+	vm_pindex_t first;
 	vm_reserv_t rv;
 	int index;
 
@@ -859,45 +877,12 @@ out:
 	}
 
 	/*
-	 * Could a reservation fit between the first index to the left that
-	 * can be used and the first index to the right that cannot be used?
-	 *
-	 * We must synchronize with the reserv object lock to protect the
-	 * pindex/object of the resulting reservations against rename while
-	 * we are inspecting.
+	 * Check whether an allocation including reservations can fit
+	 * between mpred and msucc.
 	 */
 	first = pindex - VM_RESERV_INDEX(object, pindex);
-	vm_reserv_object_lock(object);
-	if (mpred != NULL) {
-		if ((rv = vm_reserv_from_page(mpred))->object != object)
-			leftcap = mpred->pindex + 1;
-		else
-			leftcap = rv->pindex + VM_LEVEL_0_NPAGES;
-		if (leftcap > first) {
-			vm_reserv_object_unlock(object);
-			return (NULL);
-		}
-	}
-	if (msucc != NULL) {
-		if ((rv = vm_reserv_from_page(msucc))->object != object)
-			rightcap = msucc->pindex;
-		else
-			rightcap = rv->pindex;
-		if (first + VM_LEVEL_0_NPAGES > rightcap) {
-			vm_reserv_object_unlock(object);
-			return (NULL);
-		}
-	}
-	vm_reserv_object_unlock(object);
-
-	/*
-	 * Would the last new reservation extend past the end of the object?
-	 *
-	 * If the object is unlikely to grow don't allocate a reservation for
-	 * the tail.
-	 */
-	if ((object->flags & OBJ_ANON) == 0 &&
-	    first + VM_LEVEL_0_NPAGES > object->size)
+	if (vm_reserv_num_alloc_pages(object, first, 1, mpred, msucc) < 
+	    VM_LEVEL_0_NPAGES)
 		return (NULL);
 
 	/*