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