|
|
fd0330 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
fd0330 |
From: Daniel Axtens <dja@axtens.net>
|
|
|
fd0330 |
Date: Thu, 25 Nov 2021 02:22:46 +1100
|
|
|
fd0330 |
Subject: [PATCH] mm: Clarify grub_real_malloc()
|
|
|
fd0330 |
|
|
|
fd0330 |
When iterating through the singly linked list of free blocks,
|
|
|
fd0330 |
grub_real_malloc() uses p and q for the current and previous blocks
|
|
|
fd0330 |
respectively. This isn't super clear, so swap to using prev and cur.
|
|
|
fd0330 |
|
|
|
fd0330 |
This makes another quirk more obvious. The comment at the top of
|
|
|
fd0330 |
grub_real_malloc() might lead you to believe that the function will
|
|
|
fd0330 |
allocate from *first if there is space in that block.
|
|
|
fd0330 |
|
|
|
fd0330 |
It actually doesn't do that, and it can't do that with the current
|
|
|
fd0330 |
data structures. If we used up all of *first, we would need to change
|
|
|
fd0330 |
the ->next of the previous block to point to *first->next, but we
|
|
|
fd0330 |
can't do that because it's a singly linked list and we don't have
|
|
|
fd0330 |
access to *first's previous block.
|
|
|
fd0330 |
|
|
|
fd0330 |
What grub_real_malloc() actually does is set *first to the initial
|
|
|
fd0330 |
previous block, and *first->next is the block we try to allocate
|
|
|
fd0330 |
from. That allows us to keep all the data structures consistent.
|
|
|
fd0330 |
|
|
|
fd0330 |
Document that.
|
|
|
fd0330 |
|
|
|
fd0330 |
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
|
|
fd0330 |
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
|
|
fd0330 |
(cherry picked from commit 246ad6a44c281bb13486ddea0a26bb661db73106)
|
|
|
fd0330 |
---
|
|
|
fd0330 |
grub-core/kern/mm.c | 76 +++++++++++++++++++++++++++++------------------------
|
|
|
fd0330 |
1 file changed, 41 insertions(+), 35 deletions(-)
|
|
|
fd0330 |
|
|
|
fd0330 |
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
|
|
fd0330 |
index d8c8377578..fb20e93acf 100644
|
|
|
fd0330 |
--- a/grub-core/kern/mm.c
|
|
|
fd0330 |
+++ b/grub-core/kern/mm.c
|
|
|
fd0330 |
@@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
|
|
fd0330 |
}
|
|
|
fd0330 |
|
|
|
fd0330 |
/* Allocate the number of units N with the alignment ALIGN from the ring
|
|
|
fd0330 |
- buffer starting from *FIRST. ALIGN must be a power of two. Both N and
|
|
|
fd0330 |
- ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
|
|
|
fd0330 |
- otherwise return NULL. */
|
|
|
fd0330 |
+ * buffer given in *FIRST. ALIGN must be a power of two. Both N and
|
|
|
fd0330 |
+ * ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
|
|
|
fd0330 |
+ * otherwise return NULL.
|
|
|
fd0330 |
+ *
|
|
|
fd0330 |
+ * Note: because in certain circumstances we need to adjust the ->next
|
|
|
fd0330 |
+ * pointer of the previous block, we iterate over the singly linked
|
|
|
fd0330 |
+ * list with the pair (prev, cur). *FIRST is our initial previous, and
|
|
|
fd0330 |
+ * *FIRST->next is our initial current pointer. So we will actually
|
|
|
fd0330 |
+ * allocate from *FIRST->next first and *FIRST itself last.
|
|
|
fd0330 |
+ */
|
|
|
fd0330 |
static void *
|
|
|
fd0330 |
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
- grub_mm_header_t p, q;
|
|
|
fd0330 |
+ grub_mm_header_t cur, prev;
|
|
|
fd0330 |
|
|
|
fd0330 |
/* When everything is allocated side effect is that *first will have alloc
|
|
|
fd0330 |
magic marked, meaning that there is no room in this region. */
|
|
|
fd0330 |
@@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
|
|
fd0330 |
return 0;
|
|
|
fd0330 |
|
|
|
fd0330 |
/* Try to search free slot for allocation in this memory region. */
|
|
|
fd0330 |
- for (q = *first, p = q->next; ; q = p, p = p->next)
|
|
|
fd0330 |
+ for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
grub_off_t extra;
|
|
|
fd0330 |
|
|
|
fd0330 |
- extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
|
|
|
fd0330 |
+ extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
|
|
|
fd0330 |
if (extra)
|
|
|
fd0330 |
extra = align - extra;
|
|
|
fd0330 |
|
|
|
fd0330 |
- if (! p)
|
|
|
fd0330 |
+ if (! cur)
|
|
|
fd0330 |
grub_fatal ("null in the ring");
|
|
|
fd0330 |
|
|
|
fd0330 |
- if (p->magic != GRUB_MM_FREE_MAGIC)
|
|
|
fd0330 |
- grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic);
|
|
|
fd0330 |
+ if (cur->magic != GRUB_MM_FREE_MAGIC)
|
|
|
fd0330 |
+ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
|
|
|
fd0330 |
|
|
|
fd0330 |
- if (p->size >= n + extra)
|
|
|
fd0330 |
+ if (cur->size >= n + extra)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
- extra += (p->size - extra - n) & (~(align - 1));
|
|
|
fd0330 |
- if (extra == 0 && p->size == n)
|
|
|
fd0330 |
+ extra += (cur->size - extra - n) & (~(align - 1));
|
|
|
fd0330 |
+ if (extra == 0 && cur->size == n)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
/* There is no special alignment requirement and memory block
|
|
|
fd0330 |
is complete match.
|
|
|
fd0330 |
@@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
|
|
fd0330 |
| alloc, size=n | |
|
|
|
fd0330 |
+---------------+ v
|
|
|
fd0330 |
*/
|
|
|
fd0330 |
- q->next = p->next;
|
|
|
fd0330 |
+ prev->next = cur->next;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
- else if (align == 1 || p->size == n + extra)
|
|
|
fd0330 |
+ else if (align == 1 || cur->size == n + extra)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
/* There might be alignment requirement, when taking it into
|
|
|
fd0330 |
account memory block fits in.
|
|
|
fd0330 |
@@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
|
|
fd0330 |
| alloc, size=n | |
|
|
|
fd0330 |
+---------------+ v
|
|
|
fd0330 |
*/
|
|
|
fd0330 |
-
|
|
|
fd0330 |
- p->size -= n;
|
|
|
fd0330 |
- p += p->size;
|
|
|
fd0330 |
+ cur->size -= n;
|
|
|
fd0330 |
+ cur += cur->size;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
else if (extra == 0)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
grub_mm_header_t r;
|
|
|
fd0330 |
|
|
|
fd0330 |
- r = p + extra + n;
|
|
|
fd0330 |
+ r = cur + extra + n;
|
|
|
fd0330 |
r->magic = GRUB_MM_FREE_MAGIC;
|
|
|
fd0330 |
- r->size = p->size - extra - n;
|
|
|
fd0330 |
- r->next = p->next;
|
|
|
fd0330 |
- q->next = r;
|
|
|
fd0330 |
+ r->size = cur->size - extra - n;
|
|
|
fd0330 |
+ r->next = cur->next;
|
|
|
fd0330 |
+ prev->next = r;
|
|
|
fd0330 |
|
|
|
fd0330 |
- if (q == p)
|
|
|
fd0330 |
+ if (prev == cur)
|
|
|
fd0330 |
{
|
|
|
fd0330 |
- q = r;
|
|
|
fd0330 |
+ prev = r;
|
|
|
fd0330 |
r->next = r;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
}
|
|
|
fd0330 |
@@ -284,32 +290,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
|
|
fd0330 |
*/
|
|
|
fd0330 |
grub_mm_header_t r;
|
|
|
fd0330 |
|
|
|
fd0330 |
- r = p + extra + n;
|
|
|
fd0330 |
+ r = cur + extra + n;
|
|
|
fd0330 |
r->magic = GRUB_MM_FREE_MAGIC;
|
|
|
fd0330 |
- r->size = p->size - extra - n;
|
|
|
fd0330 |
- r->next = p;
|
|
|
fd0330 |
+ r->size = cur->size - extra - n;
|
|
|
fd0330 |
+ r->next = cur;
|
|
|
fd0330 |
|
|
|
fd0330 |
- p->size = extra;
|
|
|
fd0330 |
- q->next = r;
|
|
|
fd0330 |
- p += extra;
|
|
|
fd0330 |
+ cur->size = extra;
|
|
|
fd0330 |
+ prev->next = r;
|
|
|
fd0330 |
+ cur += extra;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
|
|
|
fd0330 |
- p->magic = GRUB_MM_ALLOC_MAGIC;
|
|
|
fd0330 |
- p->size = n;
|
|
|
fd0330 |
+ cur->magic = GRUB_MM_ALLOC_MAGIC;
|
|
|
fd0330 |
+ cur->size = n;
|
|
|
fd0330 |
|
|
|
fd0330 |
/* Mark find as a start marker for next allocation to fasten it.
|
|
|
fd0330 |
This will have side effect of fragmenting memory as small
|
|
|
fd0330 |
pieces before this will be un-used. */
|
|
|
fd0330 |
/* So do it only for chunks under 64K. */
|
|
|
fd0330 |
if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
|
|
|
fd0330 |
- || *first == p)
|
|
|
fd0330 |
- *first = q;
|
|
|
fd0330 |
+ || *first == cur)
|
|
|
fd0330 |
+ *first = prev;
|
|
|
fd0330 |
|
|
|
fd0330 |
- return p + 1;
|
|
|
fd0330 |
+ return cur + 1;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
|
|
|
fd0330 |
/* Search was completed without result. */
|
|
|
fd0330 |
- if (p == *first)
|
|
|
fd0330 |
+ if (cur == *first)
|
|
|
fd0330 |
break;
|
|
|
fd0330 |
}
|
|
|
fd0330 |
|