Blame SOURCES/0293-mm-Clarify-grub_real_malloc.patch

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