git: b68c7ebf5e63 - main - vm_reserv: extract common gap-checking code
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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);
/*