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:48 +1100
fd0330
Subject: [PATCH] mm: Document grub_free()
fd0330
fd0330
The grub_free() possesses a surprising number of quirks, and also
fd0330
uses single-letter variable names confusingly to iterate through
fd0330
the free list.
fd0330
fd0330
Document what's going on.
fd0330
fd0330
Use prev and cur to iterate over the free list.
fd0330
fd0330
Signed-off-by: Daniel Axtens <dja@axtens.net>
fd0330
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
fd0330
(cherry picked from commit 1f8d0b01738e49767d662d6426af3570a64565f0)
fd0330
---
fd0330
 grub-core/kern/mm.c | 63 ++++++++++++++++++++++++++++++++++-------------------
fd0330
 1 file changed, 41 insertions(+), 22 deletions(-)
fd0330
fd0330
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
fd0330
index db7e0b2a5b..0351171cf9 100644
fd0330
--- a/grub-core/kern/mm.c
fd0330
+++ b/grub-core/kern/mm.c
fd0330
@@ -446,54 +446,73 @@ grub_free (void *ptr)
fd0330
     }
fd0330
   else
fd0330
     {
fd0330
-      grub_mm_header_t q, s;
fd0330
+      grub_mm_header_t cur, prev;
fd0330
 
fd0330
 #if 0
fd0330
-      q = r->first;
fd0330
+      cur = r->first;
fd0330
       do
fd0330
 	{
fd0330
 	  grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n",
fd0330
-		       GRUB_FILE, __LINE__, q, q->size, q->magic);
fd0330
-	  q = q->next;
fd0330
+		       GRUB_FILE, __LINE__, cur, cur->size, cur->magic);
fd0330
+	  cur = cur->next;
fd0330
 	}
fd0330
-      while (q != r->first);
fd0330
+      while (cur != r->first);
fd0330
 #endif
fd0330
-
fd0330
-      for (s = r->first, q = s->next; q <= p || q->next >= p; s = q, q = s->next)
fd0330
+      /* Iterate over all blocks in the free ring.
fd0330
+       *
fd0330
+       * The free ring is arranged from high addresses to low
fd0330
+       * addresses, modulo wraparound.
fd0330
+       *
fd0330
+       * We are looking for a block with a higher address than p or
fd0330
+       * whose next address is lower than p.
fd0330
+       */
fd0330
+      for (prev = r->first, cur = prev->next; cur <= p || cur->next >= p;
fd0330
+	   prev = cur, cur = prev->next)
fd0330
 	{
fd0330
-	  if (q->magic != GRUB_MM_FREE_MAGIC)
fd0330
-	    grub_fatal ("free magic is broken at %p: 0x%x", q, q->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 (q <= q->next && (q > p || q->next < p))
fd0330
+	  /* Deal with wrap-around */
fd0330
+	  if (cur <= cur->next && (cur > p || cur->next < p))
fd0330
 	    break;
fd0330
 	}
fd0330
 
fd0330
+      /* mark p as free and insert it between cur and cur->next */
fd0330
       p->magic = GRUB_MM_FREE_MAGIC;
fd0330
-      p->next = q->next;
fd0330
-      q->next = p;
fd0330
+      p->next = cur->next;
fd0330
+      cur->next = p;
fd0330
 
fd0330
+      /*
fd0330
+       * If the block we are freeing can be merged with the next
fd0330
+       * free block, do that.
fd0330
+       */
fd0330
       if (p->next + p->next->size == p)
fd0330
 	{
fd0330
 	  p->magic = 0;
fd0330
 
fd0330
 	  p->next->size += p->size;
fd0330
-	  q->next = p->next;
fd0330
+	  cur->next = p->next;
fd0330
 	  p = p->next;
fd0330
 	}
fd0330
 
fd0330
-      r->first = q;
fd0330
+      r->first = cur;
fd0330
 
fd0330
-      if (q == p + p->size)
fd0330
+      /* Likewise if can be merged with the preceeding free block */
fd0330
+      if (cur == p + p->size)
fd0330
 	{
fd0330
-	  q->magic = 0;
fd0330
-	  p->size += q->size;
fd0330
-	  if (q == s)
fd0330
-	    s = p;
fd0330
-	  s->next = p;
fd0330
-	  q = s;
fd0330
+	  cur->magic = 0;
fd0330
+	  p->size += cur->size;
fd0330
+	  if (cur == prev)
fd0330
+	    prev = p;
fd0330
+	  prev->next = p;
fd0330
+	  cur = prev;
fd0330
 	}
fd0330
 
fd0330
-      r->first = q;
fd0330
+      /*
fd0330
+       * Set r->first such that the just free()d block is tried first.
fd0330
+       * (An allocation is tried from *first->next, and cur->next == p.)
fd0330
+       */
fd0330
+      r->first = cur;
fd0330
     }
fd0330
 }
fd0330