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); /*