git: da92ecbc0d8f - main - vm_phys: fix seg->end test in alloc_seg_contig
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 18 Jan 2022 18:49:20 UTC
The branch main has been updated by dougm:
URL: https://cgit.FreeBSD.org/src/commit/?id=da92ecbc0d8f4652cd5c97aace290103055c7019
commit da92ecbc0d8f4652cd5c97aace290103055c7019
Author: Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2022-01-18 18:32:46 +0000
Commit: Doug Moore <dougm@FreeBSD.org>
CommitDate: 2022-01-18 18:49:09 +0000
vm_phys: fix seg->end test in alloc_seg_contig
In vm_phys_alloc_seg_contig, in allocating multiple memory blocks for
a huge allocation, ensure that the end of the allocated range does not
exceed the upper segment limit.
Reorder a couple of checks to improve code layout.
Reviewed by: alc
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D33870
---
sys/vm/vm_phys.c | 69 +++++++++++++++++++++++++++-----------------------------
1 file changed, 33 insertions(+), 36 deletions(-)
diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c
index 6798c55cc91c..a880b7abd324 100644
--- a/sys/vm/vm_phys.c
+++ b/sys/vm/vm_phys.c
@@ -1428,47 +1428,44 @@ vm_phys_alloc_seg_contig(struct vm_phys_seg *seg, u_long npages,
fl = (*seg->free_queues)[pind];
TAILQ_FOREACH(m_ret, &fl[oind].pl, listq) {
/*
- * Is the size of this allocation request
- * larger than the largest block size?
+ * Determine if the address range starting at pa
+ * is within the given range, satisfies the
+ * given alignment, and does not cross the given
+ * boundary.
*/
- if (order >= VM_NFREEORDER) {
- /*
- * Determine if a sufficient number of
- * subsequent blocks to satisfy the
- * allocation request are free.
- */
- pa = VM_PAGE_TO_PHYS(m_ret);
- pa_end = pa + size;
- if (pa_end < pa)
- continue;
- for (;;) {
- pa += 1 << (PAGE_SHIFT +
- VM_NFREEORDER - 1);
- if (pa >= pa_end ||
- pa < seg->start ||
- pa >= seg->end)
- break;
- m = &seg->first_page[atop(pa -
- seg->start)];
- if (m->order != VM_NFREEORDER -
- 1)
- break;
- }
- /* If not, go to the next block. */
- if (pa < pa_end)
- continue;
- }
+ pa = VM_PAGE_TO_PHYS(m_ret);
+ pa_end = pa + size;
+ if (pa < low || pa_end > high ||
+ !vm_addr_ok(pa, size, alignment, boundary))
+ continue;
/*
- * Determine if the blocks are within the
- * given range, satisfy the given alignment,
- * and do not cross the given boundary.
+ * Is the size of this allocation request
+ * no more than the largest block size?
*/
- pa = VM_PAGE_TO_PHYS(m_ret);
- pa_end = pa + size;
- if (pa >= low && pa_end <= high &&
- vm_addr_ok(pa, size, alignment, boundary))
+ if (order < VM_NFREEORDER)
goto done;
+
+ /*
+ * Determine if the address range is valid
+ * (without overflow in pa_end calculation)
+ * and fits within the segment.
+ */
+ if (pa_end < pa || pa_end > seg->end)
+ continue;
+
+ /*
+ * Determine if a sufficient number of
+ * subsequent blocks to satisfy the
+ * allocation request are free.
+ */
+ do {
+ pa += 1 <<
+ (PAGE_SHIFT + VM_NFREEORDER - 1);
+ if (pa >= pa_end)
+ goto done;
+ } while (VM_NFREEORDER - 1 == seg->first_page[
+ atop(pa - seg->start)].order);
}
}
}