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