git: db8d0c0cd998 - main - kboot: Allocate a really big first segment

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 03 Feb 2023 15:50:57 UTC
The branch main has been updated by imp:

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

commit db8d0c0cd998722535f984c017acafbd78be2ba7
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-02-03 15:41:03 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-02-03 15:41:41 +0000

    kboot: Allocate a really big first segment
    
    Allocate a huge segment for the first kexec_load segments. We limit the
    lessor of:
            allocation to the size of the remaining memory segment
            45% of available memory
            95% of the memory we can allocate
    
    This allows us to have really large RAM disks. We likely need to limit
    this to the amount we actually used, though, since this can be a lot of
    memory.
    
    We have to do this complicated calculation for a few reasons: First, we
    need 2 copies of the loaded kernel in the memory: The kernel can copy
    everything to a temporary buffer. Next, malloc (via mmap) is limited to
    a certain amount due to over commit, so we have to not allocate all we
    can (only most of what we can).
    
    Sponsored by:           Netflix
    Reviewed by:            tsoome
    Differential Revision:  https://reviews.freebsd.org/D38314
---
 stand/kboot/main.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/stand/kboot/main.c b/stand/kboot/main.c
index 75c2d55c3f39..450934b72777 100644
--- a/stand/kboot/main.c
+++ b/stand/kboot/main.c
@@ -322,6 +322,7 @@ get_phys_buffer(vm_offset_t dest, const size_t len, void **buf)
 {
 	int i = 0;
 	const size_t segsize = 64*1024*1024;
+	size_t sz;
 
 	if (nkexec_segments == HOST_KEXEC_SEGMENT_MAX)
 		panic("Tried to load too many kexec segments");
@@ -332,10 +333,22 @@ get_phys_buffer(vm_offset_t dest, const size_t len, void **buf)
 			goto out;
 	}
 
-	loaded_segments[nkexec_segments].buf = host_getmem(segsize);
-	loaded_segments[nkexec_segments].bufsz = segsize;
+	sz = segsize;
+	if (nkexec_segments == 0) {
+		/* how much space does this segment have */
+		sz = space_avail(dest);
+		/* Clip to 45% of available memory (need 2 copies) */
+		sz = min(sz, rounddown2(mem_avail * 45 / 100, SEGALIGN));
+		/* And only use 95% of what we can allocate */
+		sz = min(sz, rounddown2(
+		    (commit_limit - committed_as) * 95 / 100, SEGALIGN));
+		printf("Allocating %zd MB for first segment\n", sz >> 20);
+	}
+
+	loaded_segments[nkexec_segments].buf = host_getmem(sz);
+	loaded_segments[nkexec_segments].bufsz = sz;
 	loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,SEGALIGN);
-	loaded_segments[nkexec_segments].memsz = segsize;
+	loaded_segments[nkexec_segments].memsz = sz;
 
 	i = nkexec_segments;
 	nkexec_segments++;