git: 25e25d6f1b55 - stable/14 - vm_phys_avail_split(): Tolerate split requests at boundaries

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Tue, 08 Apr 2025 13:40:42 UTC
The branch stable/14 has been updated by olce:

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

commit 25e25d6f1b55d9b48c1800dc1b5bd5e3d102a049
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2024-11-04 17:05:19 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-04-08 13:38:21 +0000

    vm_phys_avail_split(): Tolerate split requests at boundaries
    
    Previously, such requests would lead to a panic.  The only caller so far
    (vm_phys_early_startup()) actually faces the case where some address can
    be one of the chunk's boundaries and has to test it by hand.  Moreover,
    a later commit will introduce vm_phys_early_alloc_ex(), which will also
    have to deal with such boundary cases.
    
    Consequently, make this function handle boundaries by not splitting the
    chunk and returning EJUSTRETURN instead of 0 to distinguish this case
    from the "was split" result.
    
    While here, expand the panic message when the address to split is not in
    the passed chunk with available details.
    
    Reviewed by:    markj
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D48630
    
    (cherry picked from commit e1499bfff8b8c128d7b3d330f95e0c67d7c1fa77)
---
 sys/vm/vm_phys.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c
index 34a003fe0ab0..10ce7e15f12a 100644
--- a/sys/vm/vm_phys.c
+++ b/sys/vm/vm_phys.c
@@ -1671,7 +1671,13 @@ vm_phys_avail_size(int i)
 }
 
 /*
- * Split an entry at the address 'pa'.  Return zero on success or errno.
+ * Split a chunk in phys_avail[] at the address 'pa'.
+ *
+ * 'pa' must be within a chunk (slots i and i + 1) or one of its boundaries.
+ * Returns zero on actual split, in which case the two new chunks occupy slots
+ * i to i + 3, else EJUSTRETURN if 'pa' was one of the boundaries (and no split
+ * actually occurred) else ENOSPC if there are not enough slots in phys_avail[]
+ * to represent the additional chunk caused by the split.
  */
 static int
 vm_phys_avail_split(vm_paddr_t pa, int i)
@@ -1679,8 +1685,12 @@ vm_phys_avail_split(vm_paddr_t pa, int i)
 	int cnt;
 
 	vm_phys_avail_check(i);
-	if (pa <= phys_avail[i] || pa >= phys_avail[i + 1])
-		panic("vm_phys_avail_split: invalid address");
+	if (pa < phys_avail[i] || pa > phys_avail[i + 1])
+		panic("%s: Address %#jx not in range at slot %d [%#jx;%#jx].",
+		    __func__, (uintmax_t)pa, i,
+		    (uintmax_t)phys_avail[i], (uintmax_t)phys_avail[i + 1]);
+	if (pa == phys_avail[i] || pa == phys_avail[i + 1])
+		return (EJUSTRETURN);
 	cnt = vm_phys_avail_count();
 	if (cnt >= PHYS_AVAIL_ENTRIES)
 		return (ENOSPC);
@@ -1842,12 +1852,10 @@ vm_phys_early_startup(void)
 
 		for (i = 0; mem_affinity[i].end != 0; i++) {
 			idx = vm_phys_avail_find(mem_affinity[i].start);
-			if (idx != -1 &&
-			    phys_avail[idx] != mem_affinity[i].start)
+			if (idx != -1)
 				vm_phys_avail_split(mem_affinity[i].start, idx);
 			idx = vm_phys_avail_find(mem_affinity[i].end);
-			if (idx != -1 &&
-			    phys_avail[idx] != mem_affinity[i].end)
+			if (idx != -1)
 				vm_phys_avail_split(mem_affinity[i].end, idx);
 		}
 	}