Skip to contentSkip to conversation

x86/efi: defer freeing of boot services memory

PATCH In review Mike Rapoport 4 participants 11 messages Feb 25 – Mar 20

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 x86/efi: defer freeing of boot services memory

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

If the freed memory resides in the areas that memory map for them is still uninitialized, they won't be actually freed because memblock_free_late() calls memblock_free_pages() and the latter skips uninitialized pages.

Using free_reserved_area() at this point is also problematic because __free_page() accesses the buddy of the freed page and that again might end up in uninitialized part of the memory map.

Delaying the entire efi_free_boot_services() could be problematic because in addition to freeing boot services memory it updates efi.memmap without any synchronization and that's undesirable late in boot when there is concurrency.

More robust approach is to only defer freeing of the EFI boot services memory.

Split efi_free_boot_services() in two. First efi_unmap_boot_services() collects ranges that should be freed into an array then efi_free_boot_services() later frees them after deferred init is complete.

---

v1: https://lore.kernel.org/all/[email protected]
* update the commit message with correct function names (Ben)

 arch/x86/include/asm/efi.h          |  2 +-
 arch/x86/platform/efi/efi.c         |  2 +-
 arch/x86/platform/efi/quirks.c      | 55 +++++++++++++++++++++++++++--
 drivers/firmware/efi/mokvar-table.c |  2 +-
 4 files changed, 55 insertions(+), 6 deletions(-)
arch/x86/include/asm/efi.h +1 -1
index f227a70ac91f..51b4cdbea061 100644
@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);
 extern int __init efi_reuse_config(u64 tables, int nr_tables);
 extern void efi_delete_dummy_variable(void);
 extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
-extern void efi_free_boot_services(void);
+extern void efi_unmap_boot_services(void);
 
 void arch_efi_call_virt_setup(void);
 void arch_efi_call_virt_teardown(void);
arch/x86/platform/efi/efi.c +1 -1
index d00c6de7f3b7..d84c6020dda1 100644
@@ -836,7 +836,7 @@ static void __init __efi_enter_virtual_mode(void)
 	}
 
 	efi_check_for_embedded_firmwares();
-	efi_free_boot_services();
+	efi_unmap_boot_services();
 
 	if (!efi_is_mixed())
 		efi_native_runtime_setup();
arch/x86/platform/efi/quirks.c +52 -3

89 lines not on this page · raw message

drivers/firmware/efi/mokvar-table.c +1 -1
index 4ff0c2926097..6842aa96d704 100644
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
  * as an alternative to ordinary EFI variables, due to platform-dependent
  * limitations. The memory occupied by this table is marked as reserved.
  *
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
  * to guarantee that it can mark the table as reserved.
  *
  * Implicit inputs:

base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f

Signature · 1 line
2.51.0
#1 lore raw

Gentle ping?

Quoted 194 lines · Mike Rapoport

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

If the freed memory resides in the areas that memory map for them is still uninitialized, they won't be actually freed because memblock_free_late() calls memblock_free_pages() and the latter skips uninitialized pages.

Using free_reserved_area() at this point is also problematic because __free_page() accesses the buddy of the freed page and that again might end up in uninitialized part of the memory map.

Delaying the entire efi_free_boot_services() could be problematic because in addition to freeing boot services memory it updates efi.memmap without any synchronization and that's undesirable late in boot when there is concurrency.

More robust approach is to only defer freeing of the EFI boot services memory.

Split efi_free_boot_services() in two. First efi_unmap_boot_services() collects ranges that should be freed into an array then efi_free_boot_services() later frees them after deferred init is complete.

---

v1: https://lore.kernel.org/all/[email protected]
* update the commit message with correct function names (Ben)

 arch/x86/include/asm/efi.h          |  2 +-
 arch/x86/platform/efi/efi.c         |  2 +-
 arch/x86/platform/efi/quirks.c      | 55 +++++++++++++++++++++++++++--
 drivers/firmware/efi/mokvar-table.c |  2 +-
 4 files changed, 55 insertions(+), 6 deletions(-)
arch/x86/include/asm/efi.h +1 -1
index f227a70ac91f..51b4cdbea061 100644
@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);
 extern int __init efi_reuse_config(u64 tables, int nr_tables);
 extern void efi_delete_dummy_variable(void);
 extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
-extern void efi_free_boot_services(void);
+extern void efi_unmap_boot_services(void);
 
 void arch_efi_call_virt_setup(void);
 void arch_efi_call_virt_teardown(void);
arch/x86/platform/efi/efi.c +1 -1
index d00c6de7f3b7..d84c6020dda1 100644
@@ -836,7 +836,7 @@ static void __init __efi_enter_virtual_mode(void)
 	}
 
 	efi_check_for_embedded_firmwares();
-	efi_free_boot_services();
+	efi_unmap_boot_services();
 
 	if (!efi_is_mixed())
 		efi_native_runtime_setup();
arch/x86/platform/efi/quirks.c +52 -3
index 553f330198f2..35caa5746115 100644
@@ -341,7 +341,7 @@ void __init efi_reserve_boot_services(void)
 
 		/*
 		 * Because the following memblock_reserve() is paired
-		 * with memblock_free_late() for this region in
+		 * with free_reserved_area() for this region in
 		 * efi_free_boot_services(), we must be extremely
 		 * careful not to reserve, and subsequently free,
 		 * critical regions of memory (like the kernel image) or
@@ -404,17 +404,33 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)
 		pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
 }
 
-void __init efi_free_boot_services(void)
+struct efi_freeable_range {
+	u64 start;
+	u64 end;
+};
+
+static struct efi_freeable_range *ranges_to_free;
+
+void __init efi_unmap_boot_services(void)
 {
 	struct efi_memory_map_data data = { 0 };
 	efi_memory_desc_t *md;
 	int num_entries = 0;
+	int idx = 0;
+	size_t sz;
 	void *new, *new_md;
 
 	/* Keep all regions for /sys/kernel/debug/efi */
 	if (efi_enabled(EFI_DBG))
 		return;
 
+	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+	ranges_to_free = kzalloc(sz, GFP_KERNEL);
+	if (!ranges_to_free) {
+		pr_err("Failed to allocate storage for freeable EFI regions\n");
+		return;
+	}
+
 	for_each_efi_memory_desc(md) {
 		unsigned long long start = md->phys_addr;
 		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -471,7 +487,15 @@ void __init efi_free_boot_services(void)
 			start = SZ_1M;
 		}
 
-		memblock_free_late(start, size);
+		/*
+		 * With CONFIG_DEFERRED_STRUCT_PAGE_INIT parts of the memory
+		 * map are still not initialized and we can't reliably free
+		 * memory here.
+		 * Queue the ranges to free at a later point.
+		 */
+		ranges_to_free[idx].start = start;
+		ranges_to_free[idx].end = start + size;
+		idx++;
 	}
 
 	if (!num_entries)
@@ -512,6 +536,31 @@ void __init efi_free_boot_services(void)
 	}
 }
 
+static int __init efi_free_boot_services(void)
+{
+	struct efi_freeable_range *range = ranges_to_free;
+	unsigned long freed = 0;
+
+	if (!ranges_to_free)
+		return 0;
+
+	while (range->start) {
+		void *start = phys_to_virt(range->start);
+		void *end = phys_to_virt(range->end);
+
+		free_reserved_area(start, end, -1, NULL);
+		freed += (end - start);
+		range++;
+	}
+	kfree(ranges_to_free);
+
+	if (freed)
+		pr_info("Freeing EFI boot services memory: %ldK\n", freed / SZ_1K);
+
+	return 0;
+}
+arch_initcall(efi_free_boot_services);
+
 /*
  * A number of config table entries get remapped to virtual addresses
  * after entering EFI virtual mode. However, the kexec kernel requires
drivers/firmware/efi/mokvar-table.c +1 -1
index 4ff0c2926097..6842aa96d704 100644
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
  * as an alternative to ordinary EFI variables, due to platform-dependent
  * limitations. The memory occupied by this table is marked as reserved.
  *
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
  * to guarantee that it can mark the table as reserved.
  *
  * Implicit inputs:

base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f

Signature · 1 line
2.51.0
Signature · 2 lines
Sincerely yours,
Mike.
#2 lore raw
Quoted 1 line · Mike Rapoport

Gentle ping?

Ard, I _think_ this is one of the efi things in arch/x86 that you normally wrangle. Are you planning to grab this?

maintainer
#3 lore raw
Quoted 5 lines · Dave Hansen
Quoted 1 line · Mike Rapoport

Gentle ping?

Ard, I _think_ this is one of the efi things in arch/x86 that you normally wrangle. Are you planning to grab this?

Yes, I will pick it up. I'm planning some cleanup on top, but those will not be fixes anyway so this should go in on its own merit.

maintainer
#4 lore raw
In reply to Mike Rapoport
Quoted 9 lines · Mike Rapoport

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

Quoted 7 lines

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

Putting a fixes tag referencing a patch that dates back to 2011 doesn't seem that useful here. Is this really an issue that goes all the way back? Or did a later change trigger the actual leak?

#5 lore raw
Quoted 15 lines · Ard Biesheuvel
Quoted 13 lines · Mike Rapoport

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Quoted 7 lines
Quoted 3 lines

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

Putting a fixes tag referencing a patch that dates back to 2011 doesn't seem that useful here. Is this really an issue that goes all the way back? Or did a later change trigger the actual leak?

You are right, the leak was triggered later by addition of deferred initialization of struct pages which is about 4.2 time.

So fixes tag is wrong indeed, but all the currently maintained stable versions are affected.

Signature · 2 lines
Sincerely yours,
Mike.
maintainer
#6 lore raw
Quoted 24 lines · Mike Rapoport
Quoted 15 lines · Ard Biesheuvel
Quoted 13 lines · Mike Rapoport

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Quoted 7 lines
Quoted 3 lines

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

Putting a fixes tag referencing a patch that dates back to 2011 doesn't seem that useful here. Is this really an issue that goes all the way back? Or did a later change trigger the actual leak?

Quoted 6 lines

You are right, the leak was triggered later by addition of deferred initialization of struct pages which is about 4.2 time.

So fixes tag is wrong indeed, but all the currently maintained stable versions are affected.

Fair enough. It's already in -next so I will just leave it as is.

#7 lore raw
In reply to Mike Rapoport

Hi,

Quoted 108 lines · Mike Rapoport

From: "Mike Rapoport (Microsoft)" <[email protected]>

efi_free_boot_services() frees memory occupied by EFI_BOOT_SERVICES_CODE and EFI_BOOT_SERVICES_DATA using memblock_free_late().

There are two issue with that: memblock_free_late() should be used for memory allocated with memblock_alloc() while the memory reserved with memblock_reserve() should be freed with free_reserved_area().

More acutely, with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y efi_free_boot_services() is called before deferred initialization of the memory map is complete.

Benjamin Herrenschmidt reports that this causes a leak of ~140MB of RAM on EC2 t3a.nano instances which only have 512MB or RAM.

If the freed memory resides in the areas that memory map for them is still uninitialized, they won't be actually freed because memblock_free_late() calls memblock_free_pages() and the latter skips uninitialized pages.

Using free_reserved_area() at this point is also problematic because __free_page() accesses the buddy of the freed page and that again might end up in uninitialized part of the memory map.

Delaying the entire efi_free_boot_services() could be problematic because in addition to freeing boot services memory it updates efi.memmap without any synchronization and that's undesirable late in boot when there is concurrency.

More robust approach is to only defer freeing of the EFI boot services memory.

Split efi_free_boot_services() in two. First efi_unmap_boot_services() collects ranges that should be freed into an array then efi_free_boot_services() later frees them after deferred init is complete.

---

v1: https://lore.kernel.org/all/[email protected]
* update the commit message with correct function names (Ben)

 arch/x86/include/asm/efi.h          |  2 +-
 arch/x86/platform/efi/efi.c         |  2 +-
 arch/x86/platform/efi/quirks.c      | 55 +++++++++++++++++++++++++++--
 drivers/firmware/efi/mokvar-table.c |  2 +-
 4 files changed, 55 insertions(+), 6 deletions(-)
arch/x86/include/asm/efi.h +1 -1
index f227a70ac91f..51b4cdbea061 100644
@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);
 extern int __init efi_reuse_config(u64 tables, int nr_tables);
 extern void efi_delete_dummy_variable(void);
 extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
-extern void efi_free_boot_services(void);
+extern void efi_unmap_boot_services(void);
 
 void arch_efi_call_virt_setup(void);
 void arch_efi_call_virt_teardown(void);
arch/x86/platform/efi/efi.c +1 -1
index d00c6de7f3b7..d84c6020dda1 100644
@@ -836,7 +836,7 @@ static void __init __efi_enter_virtual_mode(void)
 	}
 
 	efi_check_for_embedded_firmwares();
-	efi_free_boot_services();
+	efi_unmap_boot_services();
 
 	if (!efi_is_mixed())
 		efi_native_runtime_setup();
arch/x86/platform/efi/quirks.c +9 -2
index 553f330198f2..35caa5746115 100644
@@ -341,7 +341,7 @@ void __init efi_reserve_boot_services(void)
 
 		/*
 		 * Because the following memblock_reserve() is paired
-		 * with memblock_free_late() for this region in
+		 * with free_reserved_area() for this region in
 		 * efi_free_boot_services(), we must be extremely
 		 * careful not to reserve, and subsequently free,
 		 * critical regions of memory (like the kernel image) or
@@ -404,17 +404,33 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)
 		pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
 }
 
-void __init efi_free_boot_services(void)
+struct efi_freeable_range {
+	u64 start;
+	u64 end;
+};
+
+static struct efi_freeable_range *ranges_to_free;
+
+void __init efi_unmap_boot_services(void)
 {
 	struct efi_memory_map_data data = { 0 };
 	efi_memory_desc_t *md;

arch/x86/platform/efi/quirks.c static void __init efi_unmap_pages(efi_memory_desc_t *md) · line 427

Quoted 10 lines
arch/x86/platform/efi/quirks.c +3 -0
 	int num_entries = 0;
+	int idx = 0;
+	size_t sz;
 	void *new, *new_md;
 
 	/* Keep all regions for /sys/kernel/debug/efi */
 	if (efi_enabled(EFI_DBG))
 		return;
 
+	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;

Was this possibly supposed to be

	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
				       ^		     ^

?

Thanks,
Guenter

Quoted 75 lines
arch/x86/platform/efi/quirks.c +40 -1
+	ranges_to_free = kzalloc(sz, GFP_KERNEL);
+	if (!ranges_to_free) {
+		pr_err("Failed to allocate storage for freeable EFI regions\n");
+		return;
+	}
+
 	for_each_efi_memory_desc(md) {
 		unsigned long long start = md->phys_addr;
 		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -471,7 +487,15 @@ void __init efi_free_boot_services(void)
 			start = SZ_1M;
 		}
 
-		memblock_free_late(start, size);
+		/*
+		 * With CONFIG_DEFERRED_STRUCT_PAGE_INIT parts of the memory
+		 * map are still not initialized and we can't reliably free
+		 * memory here.
+		 * Queue the ranges to free at a later point.
+		 */
+		ranges_to_free[idx].start = start;
+		ranges_to_free[idx].end = start + size;
+		idx++;
 	}
 
 	if (!num_entries)
@@ -512,6 +536,31 @@ void __init efi_free_boot_services(void)
 	}
 }
 
+static int __init efi_free_boot_services(void)
+{
+	struct efi_freeable_range *range = ranges_to_free;
+	unsigned long freed = 0;
+
+	if (!ranges_to_free)
+		return 0;
+
+	while (range->start) {
+		void *start = phys_to_virt(range->start);
+		void *end = phys_to_virt(range->end);
+
+		free_reserved_area(start, end, -1, NULL);
+		freed += (end - start);
+		range++;
+	}
+	kfree(ranges_to_free);
+
+	if (freed)
+		pr_info("Freeing EFI boot services memory: %ldK\n", freed / SZ_1K);
+
+	return 0;
+}
+arch_initcall(efi_free_boot_services);
+
 /*
  * A number of config table entries get remapped to virtual addresses
  * after entering EFI virtual mode. However, the kexec kernel requires
drivers/firmware/efi/mokvar-table.c +1 -1
index 4ff0c2926097..6842aa96d704 100644
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
  * as an alternative to ordinary EFI variables, due to platform-dependent
  * limitations. The memory occupied by this table is marked as reserved.
  *
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
  * to guarantee that it can mark the table as reserved.
  *
  * Implicit inputs:

base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f

Signature · 1 line
2.51.
#8 lore raw
Quoted 15 lines · Guenter Roeck

Hi,

Quoted 13 lines
(quoted diff) +3 -0
+void __init efi_unmap_boot_services(void)
 {
 	struct efi_memory_map_data data = { 0 };
 	efi_memory_desc_t *md;
 	int num_entries = 0;
+	int idx = 0;
+	size_t sz;
 	void *new, *new_md;
 
 	/* Keep all regions for /sys/kernel/debug/efi */
 	if (efi_enabled(EFI_DBG))
 		return;
Quoted 6 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;

Was this possibly supposed to be

	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
				       ^		     ^

?

Yes, thanks for catching this.

@Ard, can you please pick the fix:

From 8fc5c5e828e7d127e6210bc9952451300591cdce Mon Sep 17 00:00:00 2001
From: "Mike Rapoport (Microsoft)" <[email protected]>
Date: Fri, 20 Mar 2026 15:59:48 +0200
Subject: [PATCH] x86/efi: efi_unmap_boot_services: fix calculation of
ranges_to_free size

ranges_to_free array should have enough room to store the entire EFI memmap plus an extra element for NULL entry.
The calculation of this array size wrongly adds 1 to the overall size instead of adding 1 to the number of elements.

Add parentheses to properly size the array.

Fixes a4b0bf6a40f3 ("x86/efi: defer freeing of boot services memory")
---
 arch/x86/platform/efi/quirks.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/platform/efi/quirks.c +1 -1
index 35caa5746115..79f0818131e8 100644
@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)
 	if (efi_enabled(EFI_DBG))
 		return;
 
-	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
 	ranges_to_free = kzalloc(sz, GFP_KERNEL);
 	if (!ranges_to_free) {
 		pr_err("Failed to allocate storage for freeable EFI regions\n");
Signature · 1 line
2.53.0
maintainer
#9 lore raw
Quoted 23 lines · Mike Rapoport
Quoted 15 lines · Guenter Roeck

Hi,

Quoted 13 lines
(quoted diff) +3 -0
+void __init efi_unmap_boot_services(void)
 {
 	struct efi_memory_map_data data = { 0 };
 	efi_memory_desc_t *md;
 	int num_entries = 0;
+	int idx = 0;
+	size_t sz;
 	void *new, *new_md;
 
 	/* Keep all regions for /sys/kernel/debug/efi */
 	if (efi_enabled(EFI_DBG))
 		return;
Quoted 6 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;

Was this possibly supposed to be

	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
				       ^		     ^

?

Quoted 4 lines

Yes, thanks for catching this.

@Ard, can you please pick the fix:

Yep, queued up now.

Thanks for the fix.

Quoted 33 lines

From 8fc5c5e828e7d127e6210bc9952451300591cdce Mon Sep 17 00:00:00 2001
From: "Mike Rapoport (Microsoft)" <[email protected]>
Date: Fri, 20 Mar 2026 15:59:48 +0200
Subject: [PATCH] x86/efi: efi_unmap_boot_services: fix calculation of
ranges_to_free size

ranges_to_free array should have enough room to store the entire EFI memmap plus an extra element for NULL entry.
The calculation of this array size wrongly adds 1 to the overall size instead of adding 1 to the number of elements.

Add parentheses to properly size the array.

Fixes a4b0bf6a40f3 ("x86/efi: defer freeing of boot services memory")
---
 arch/x86/platform/efi/quirks.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/platform/efi/quirks.c +1 -1
index 35caa5746115..79f0818131e8 100644
@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)
 	if (efi_enabled(EFI_DBG))
 		return;
 
-	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
 	ranges_to_free = kzalloc(sz, GFP_KERNEL);
 	if (!ranges_to_free) {
 		pr_err("Failed to allocate storage for freeable EFI regions\n");
#10 lore raw
In reply to Mike Rapoport
Quoted 16 lines · Mike Rapoport
Quoted 15 lines · Guenter Roeck

Hi,

Quoted 13 lines
(quoted diff) +3 -0
+void __init efi_unmap_boot_services(void)
  {
  	struct efi_memory_map_data data = { 0 };
  	efi_memory_desc_t *md;
  	int num_entries = 0;
+	int idx = 0;
+	size_t sz;
  	void *new, *new_md;
 
  	/* Keep all regions for /sys/kernel/debug/efi */
  	if (efi_enabled(EFI_DBG))
  		return;
Quoted 9 lines
Quoted 6 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;

Was this possibly supposed to be

	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
				       ^		     ^

?

Yes, thanks for catching this.

Thanks for confirming.

Just for the record, it wasn't really me, it was an instance of Sashiko running on the LTS backport of the patch.

Guenter

Quoted 35 lines

@Ard, can you please pick the fix:

From 8fc5c5e828e7d127e6210bc9952451300591cdce Mon Sep 17 00:00:00 2001
From: "Mike Rapoport (Microsoft)" <[email protected]>
Date: Fri, 20 Mar 2026 15:59:48 +0200
Subject: [PATCH] x86/efi: efi_unmap_boot_services: fix calculation of
ranges_to_free size

ranges_to_free array should have enough room to store the entire EFI memmap plus an extra element for NULL entry.
The calculation of this array size wrongly adds 1 to the overall size instead of adding 1 to the number of elements.

Add parentheses to properly size the array.

Fixes a4b0bf6a40f3 ("x86/efi: defer freeing of boot services memory")
---
  arch/x86/platform/efi/quirks.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/platform/efi/quirks.c +1 -1
index 35caa5746115..79f0818131e8 100644
@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)
  	if (efi_enabled(EFI_DBG))
  		return;
 
-	sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+	sz = sizeof(*ranges_to_free) * (efi.memmap.nr_map + 1);
  	ranges_to_free = kzalloc(sz, GFP_KERNEL);
  	if (!ranges_to_free) {
  		pr_err("Failed to allocate storage for freeable EFI regions\n");