Update mm fixes from upstream

Signed-off-by: Robbie Harwood <rharwood@redhat.com>
This commit is contained in:
Robbie Harwood 2023-02-20 16:49:18 +00:00
parent b86fd390b8
commit 5c83f50804
5 changed files with 277 additions and 1 deletions

View file

@ -0,0 +1,145 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang.id@gmail.com>
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 <zhangboyang.id@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(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 <adress space size> - 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;
}

View file

@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang.id@gmail.com>
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 <zhangboyang.id@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(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;

View file

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zhang Boyang <zhangboyang.id@gmail.com>
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 <zhangboyang.id@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(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 <adress space size> - 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;

View file

@ -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

View file

@ -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 <rharwood@redhat.com> - 2.06-88
- Update mm fixes from upstream
* Thu Feb 16 2023 Robbie Harwood <rharwood@redhat.com> - 2.06-87
- Fix disk sector size computation