diff --git a/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch b/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch new file mode 100644 index 0000000..456f8f7 --- /dev/null +++ b/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch @@ -0,0 +1,145 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:31 +0800 +Subject: [PATCH] mm: Adjust new region size to take management overhead into + account + +When grub_memalign() encounters out-of-memory, it will try +grub_mm_add_region_fn() to request more memory from system firmware. +However, the size passed to it doesn't take region management overhead +into account. Adding a memory area of "size" bytes may result in a heap +region of less than "size" bytes really available. Thus, the new region +may not be adequate for current allocation request, confusing +out-of-memory handling code. + +This patch introduces GRUB_MM_MGMT_OVERHEAD to address the region +management overhead (e.g. metadata, padding). The value of this new +constant must be large enough to make sure grub_memalign(align, size) +always succeeds after a successful call to + grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD), +for any given addr and size (assuming no integer overflow). + +The size passed to grub_mm_add_region_fn() is now correctly adjusted, +thus if grub_mm_add_region_fn() succeeded, current allocation request +can always succeed. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 2282cbfe5aa1ff6c1bbcbdcd2003089ad7c03ba3) +--- + grub-core/kern/mm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 61 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index da1ac9427c..f29a3e5cbd 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -83,6 +83,46 @@ + + + ++/* ++ * GRUB_MM_MGMT_OVERHEAD is an upper bound of management overhead of ++ * each region, with any possible padding taken into account. ++ * ++ * The value must be large enough to make sure grub_memalign(align, size) ++ * always succeeds after a successful call to ++ * grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD), ++ * for any given addr, align and size (assuming no interger overflow). ++ * ++ * The worst case which has maximum overhead is shown in the figure below: ++ * ++ * +-- addr ++ * v |<- size + align ->| ++ * +---------+----------------+----------------+------------------+---------+ ++ * | padding | grub_mm_region | grub_mm_header | usable bytes | padding | ++ * +---------+----------------+----------------+------------------+---------+ ++ * |<- a ->|<- b ->|<- c ->|<- d ->|<- e ->| ++ * ^ ++ * b == sizeof (struct grub_mm_region) | / Assuming no other suitable ++ * c == sizeof (struct grub_mm_header) | | block is available, then: ++ * d == size + align +-| If align == 0, this will be ++ * | the pointer returned by next ++ * Assuming addr % GRUB_MM_ALIGN == 1, then: | grub_memalign(align, size). ++ * a == GRUB_MM_ALIGN - 1 | If align > 0, this chunk may ++ * | need to be split to fulfill ++ * Assuming d % GRUB_MM_ALIGN == 1, then: | alignment requirements, and ++ * e == GRUB_MM_ALIGN - 1 | the returned pointer may be ++ * \ inside these usable bytes. ++ * Therefore, the maximum overhead is: ++ * a + b + c + e == (GRUB_MM_ALIGN - 1) + sizeof (struct grub_mm_region) ++ * + sizeof (struct grub_mm_header) + (GRUB_MM_ALIGN - 1) ++ */ ++#define GRUB_MM_MGMT_OVERHEAD ((GRUB_MM_ALIGN - 1) \ ++ + sizeof (struct grub_mm_region) \ ++ + sizeof (struct grub_mm_header) \ ++ + (GRUB_MM_ALIGN - 1)) ++ ++/* The size passed to grub_mm_add_region_fn() is aligned up by this value. */ ++#define GRUB_MM_HEAP_GROW_ALIGN 4096 ++ + grub_mm_region_t grub_mm_base; + grub_mm_add_region_func_t grub_mm_add_region_fn; + +@@ -230,6 +270,11 @@ grub_mm_init_region (void *addr, grub_size_t size) + + grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", + addr, size); ++ /* ++ * If you want to modify the code below, please also take a look at ++ * GRUB_MM_MGMT_OVERHEAD and make sure it is synchronized with the code. ++ */ ++ + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + +@@ -410,6 +455,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + { + grub_mm_region_t r; + grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; ++ grub_size_t grow; + int count = 0; + + if (!grub_mm_base) +@@ -418,10 +464,22 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (size > ~(grub_size_t) align) + goto fail; + ++ /* ++ * Pre-calculate the necessary size of heap growth (if applicable), ++ * with region management overhead taken into account. ++ */ ++ if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) ++ goto fail; ++ ++ /* Align up heap growth to make it friendly to CPU/MMU. */ ++ if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) ++ goto fail; ++ grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ + /* We currently assume at least a 32-bit grub_size_t, + so limiting allocations to - 1MiB + in name of sanity is beneficial. */ +- if ((size + align) > ~(grub_size_t) 0x100000) ++ if (grow > ~(grub_size_t) 0x100000) + goto fail; + + align = (align >> GRUB_MM_ALIGN_LOG2); +@@ -447,7 +505,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + + if (grub_mm_add_region_fn != NULL && +- grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) ++ grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; + + /* fallthrough */ +@@ -462,7 +520,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + * Try again even if this fails, in case it was able to partially + * satisfy the request + */ +- grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); ++ grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_NONE); + goto again; + } + diff --git a/0321-mm-Preallocate-some-space-when-adding-new-regions.patch b/0321-mm-Preallocate-some-space-when-adding-new-regions.patch new file mode 100644 index 0000000..291092d --- /dev/null +++ b/0321-mm-Preallocate-some-space-when-adding-new-regions.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:32 +0800 +Subject: [PATCH] mm: Preallocate some space when adding new regions + +When grub_memalign() encounters out-of-memory, it will try +grub_mm_add_region_fn() to request more memory from system firmware. +However, it doesn't preallocate memory space for future allocation +requests. In extreme cases, it requires one call to +grub_mm_add_region_fn() for each memory allocation request. This can +be very slow. + +This patch introduces GRUB_MM_HEAP_GROW_EXTRA, the minimal heap growth +granularity. The new region size is now set to the bigger one of its +original value and GRUB_MM_HEAP_GROW_EXTRA. Thus, it will result in some +memory space preallocated if current allocations request is small. + +The value of GRUB_MM_HEAP_GROW_EXTRA is set to 1MB. If this value is +smaller, the cost of small memory allocations will be higher. If this +value is larger, more memory will be wasted and it might cause +out-of-memory on machines with small amount of RAM. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 21869baec15239b6d99122b32b14a778af4c754f) +--- + grub-core/kern/mm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index f29a3e5cbd..cc8a4703bc 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -123,6 +123,9 @@ + /* The size passed to grub_mm_add_region_fn() is aligned up by this value. */ + #define GRUB_MM_HEAP_GROW_ALIGN 4096 + ++/* Minimal heap growth granularity when existing heap space is exhausted. */ ++#define GRUB_MM_HEAP_GROW_EXTRA 0x100000 ++ + grub_mm_region_t grub_mm_base; + grub_mm_add_region_func_t grub_mm_add_region_fn; + +@@ -471,6 +474,9 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) + goto fail; + ++ /* Preallocate some extra space if heap growth is small. */ ++ grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); ++ + /* Align up heap growth to make it friendly to CPU/MMU. */ + if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) + goto fail; diff --git a/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch b/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch new file mode 100644 index 0000000..fe6b3e1 --- /dev/null +++ b/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:33 +0800 +Subject: [PATCH] mm: Avoid complex heap growth math in hot path + +We do a lot of math about heap growth in hot path of grub_memalign(). +However, the result is only used if out of memory is encountered, which +is seldom. + +This patch moves these calculations away from hot path. These +calculations are now only done if out of memory is encountered. This +change can also help compiler to optimize integer overflow checks away. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 65bc45963014773e2062ccc63ff34a089d2e352e) +--- + grub-core/kern/mm.c | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index cc8a4703bc..630d7be0e2 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -467,20 +467,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (size > ~(grub_size_t) align) + goto fail; + +- /* +- * Pre-calculate the necessary size of heap growth (if applicable), +- * with region management overhead taken into account. +- */ +- if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) +- goto fail; +- +- /* Preallocate some extra space if heap growth is small. */ +- grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); +- +- /* Align up heap growth to make it friendly to CPU/MMU. */ +- if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) +- goto fail; +- grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ grow = size + align; + + /* We currently assume at least a 32-bit grub_size_t, + so limiting allocations to - 1MiB +@@ -510,6 +497,25 @@ grub_memalign (grub_size_t align, grub_size_t size) + /* Request additional pages, contiguous */ + count++; + ++ /* ++ * Calculate the necessary size of heap growth (if applicable), ++ * with region management overhead taken into account. ++ */ ++ if (grub_add (grow, GRUB_MM_MGMT_OVERHEAD, &grow)) ++ goto fail; ++ ++ /* Preallocate some extra space if heap growth is small. */ ++ grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); ++ ++ /* Align up heap growth to make it friendly to CPU/MMU. */ ++ if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) ++ goto fail; ++ grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ ++ /* Do the same sanity check again. */ ++ if (grow > ~(grub_size_t) 0x100000) ++ goto fail; ++ + if (grub_mm_add_region_fn != NULL && + grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; diff --git a/grub.patches b/grub.patches index 02e4c7b..510ab16 100644 --- a/grub.patches +++ b/grub.patches @@ -317,3 +317,6 @@ Patch0316: 0316-ieee1275-implement-vec5-for-cas-negotiation.patch Patch0317: 0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch Patch0318: 0318-powerpc-Drop-Open-Hack-Ware.patch Patch0319: 0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch +Patch0320: 0320-mm-Adjust-new-region-size-to-take-management-overhea.patch +Patch0321: 0321-mm-Preallocate-some-space-when-adding-new-regions.patch +Patch0322: 0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch diff --git a/grub2.spec b/grub2.spec index 85c783d..a465a39 100644 --- a/grub2.spec +++ b/grub2.spec @@ -17,7 +17,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 87%{?dist} +Release: 88%{?dist} Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -544,6 +544,9 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Mon Feb 20 2023 Robbie Harwood - 2.06-88 +- Update mm fixes from upstream + * Thu Feb 16 2023 Robbie Harwood - 2.06-87 - Fix disk sector size computation