memblock: improve late freeing of reserved memory
Subsystems (16)
Mike Rapoport
maintainerv2 cover memblock: improve late freeing of reserved memory
From: "Mike Rapoport (Microsoft)" <[email protected]>
Hi,
Following a recent discussion about leaks in x86 EFI [1], I audited usage of memblock_free_late() and free_reserved_area() and made some imporovements how we handle late freeing of the memory allocated with memblock.
[1] https://lore.kernel.org/all/ec2aaef14783869b3be6e3c253b2dcbf67dbc12a.camel@kernel.crashing.org/
v2 changes:
* fix UAF issue in memblock_discard() reported by 0day and sashiko
* address relevant sashiko comments
* squash memblock test stubs changes into the commit with core updates
v1: https://lore.kernel.org/all/[email protected]
Mike Rapoport (Microsoft) (9):
memblock: reserve_mem: fix end caclulation in reserve_mem_release_by_name()
powerpc: fadump: pair alloc_pages_exact() with free_pages_exact()
powerpc: opal-core: pair alloc_pages_exact() with free_pages_exact()
mm: move free_reserved_area() to mm/memblock.c
memblock: make free_reserved_area() more robust
memblock: extract page freeing from free_reserved_area() into a helper
memblock: make free_reserved_area() update memblock if ARCH_KEEP_MEMBLOCK=y memblock, treewide: make memblock_free() handle late freeing
memblock: warn when freeing reserved memory before memory map is initialized
arch/arm64/mm/init.c | 3 - arch/powerpc/kernel/fadump.c | 16 +-- arch/powerpc/platforms/powernv/opal-core.c | 11 +- arch/sparc/kernel/mdesc.c | 4 +- arch/x86/kernel/setup.c | 2 +- arch/x86/platform/efi/memmap.c | 5 +- arch/x86/platform/efi/quirks.c | 2 +- drivers/firmware/efi/apple-properties.c | 2 +- drivers/of/kexec.c | 2 +- include/linux/memblock.h | 2 - init/initramfs.c | 7 -- kernel/dma/swiotlb.c | 6 +- lib/bootconfig.c | 2 +- mm/internal.h | 10 ++ mm/kfence/core.c | 4 +- mm/memblock.c | 124 +++++++++++++++------ mm/page_alloc.c | 46 -------- tools/include/linux/mm.h | 1 + tools/testing/memblock/internal.h | 34 +++++- 19 files changed, 144 insertions(+), 139 deletions(-)
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 1/9 memblock: reserve_mem: fix end caclulation in reserve_mem_release_by_name()
From: "Mike Rapoport (Microsoft)" <[email protected]>
free_reserved_area() expects end parameter to point to the first address after the area, but reserve_mem_release_by_name() passes it the last address inside the area.
Remove subtraction of one in calculation of the area end.
--- mm/memblock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memblock.c +1 -1
@@ -2434,7 +2434,7 @@ int reserve_mem_release_by_name(const char *name)return 0 ; start =phys_to_virt (map->start); - end = start + map->size -1 ; + end = start + map->size;snprintf (buf,sizeof (buf),"reserve_mem:%s" , name);free_reserved_area (start, end,0 , buf); map->size =0 ;
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 2/9 powerpc: fadump: pair alloc_pages_exact() with free_pages_exact()
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
fadump allocates buffers with alloc_pages_exact(), but then marks them as reserved and frees using free_reserved_area().
This is completely unnecessary and the pages allocated with alloc_pages_exact() can be naturally freed with free_pages_exact().
Replace freeing of memory in fadump_free_buffer() with free_pages_exact() and simplify allocation code so that it won't mark allocated pages as reserved.
--- arch/powerpc/kernel/fadump.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
arch/powerpc/kernel/fadump.c +2 -14
@@ -775,24 +775,12 @@ void __init fadump_update_elfcore_header(char *bufp)static void *__init fadump_alloc_buffer (unsigned long size) { -unsigned long count, i; -struct page *page; -void *vaddr; - - vaddr =alloc_pages_exact (size,GFP_KERNEL | __GFP_ZERO); -if (!vaddr) -return NULL ; - - count =PAGE_ALIGN (size) /PAGE_SIZE ; - page =virt_to_page (vaddr); -for (i =0 ; i < count; i++) -mark_page_reserved (page + i); -return vaddr; +return alloc_pages_exact (size,GFP_KERNEL | __GFP_ZERO); }static void fadump_free_buffer (unsigned long vaddr,unsigned long size) { -free_reserved_area ((void *)vaddr, (void *)(vaddr + size),-1 ,NULL ); +free_pages_exact ((void *)vaddr, size); }s32 __init fadump_setup_cpu_notes_buf (u32 num_cpus)
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 3/9 powerpc: opal-core: pair alloc_pages_exact() with free_pages_exact()
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
opal-core allocates buffers with alloc_pages_exact(), but then marks them as reserved and frees using free_reserved_area().
This is completely unnecessary and the pages allocated with alloc_pages_exact() can be naturally freed with free_pages_exact().
Replace freeing of memory in opalcore_cleanup() with free_pages_exact() and simplify allocation code so that it won't mark allocated pages as reserved.
--- arch/powerpc/platforms/powernv/opal-core.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
arch/powerpc/platforms/powernv/opal-core.c +1 -10
@@ -303,7 +303,6 @@ static int __init create_opalcore(void)struct device_node *dn;struct opalcore *new;loff_t opalcore_off; -struct page *page;Elf64_Phdr *phdr;Elf64_Ehdr *elf;int i, ret;
@@ -328,11 +327,6 @@ static int __init create_opalcore(void) oc_conf->opalcorebuf_sz =0 ;return -ENOMEM ; } - count = oc_conf->opalcorebuf_sz /PAGE_SIZE ; - page =virt_to_page (oc_conf->opalcorebuf); -for (i =0 ; i < count; i++) -mark_page_reserved (page + i); -pr_debug ("opalcorebuf = 0x%llx\n" , (u64 )oc_conf->opalcorebuf);/* Read OPAL related device-tree entries */
@@ -437,10 +431,7 @@ static void opalcore_cleanup(void)/* free the buffer used for setting up OPAL core */ if (oc_conf->opalcorebuf) { -void *end = (void *)((u64 )oc_conf->opalcorebuf + - oc_conf->opalcorebuf_sz); - -free_reserved_area (oc_conf->opalcorebuf, end,-1 ,NULL ); +free_pages_exact (oc_conf->opalcorebuf, oc_conf->opalcorebuf_sz); oc_conf->opalcorebuf =NULL ; oc_conf->opalcorebuf_sz =0 ; }
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 4/9 mm: move free_reserved_area() to mm/memblock.c
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
free_reserved_area() is related to memblock as it frees reserved memory back to the buddy allocator, similar to what memblock_free_late() does.
Move free_reserved_area() to mm/memblock.c to prepare for further consolidation of the functions that free reserved memory.
No functional changes.
--- mm/memblock.c | 37 ++++++++++++++++++++++++++++++- mm/page_alloc.c | 36 ------------------------------ tools/include/linux/mm.h | 1 + tools/testing/memblock/internal.h | 34 +++++++++++++++++++++++++--- 4 files changed, 68 insertions(+), 40 deletions(-)
mm/memblock.c +36 -1
@@ -893,6 +893,42 @@ int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)return memblock_remove_range (&memblock.memory, base, size); } +unsigned long free_reserved_area (void *start,void *end,int poison,const char *s) +{ +void *pos; +unsigned long pages =0 ; + + start = (void *)PAGE_ALIGN ((unsigned long )start); + end = (void *)((unsigned long )end &PAGE_MASK ); +for (pos = start; pos < end; pos +=PAGE_SIZE , pages++) { +struct page *page =virt_to_page (pos); +void *direct_map_addr; + +/* +* 'direct_map_addr' might be different from 'pos' +* because some architectures' virt_to_page() +* work with aliases. Getting the direct map +* address ensures that we get a _writeable_ +* alias for the memset(). +*/ + direct_map_addr =page_address (page); +/* +* Perform a kasan-unchecked memset() since this memory +* has not been initialized. +*/ + direct_map_addr =kasan_reset_tag (direct_map_addr); +if ((unsigned int )poison <=0xFF ) +memset (direct_map_addr, poison,PAGE_SIZE ); + +free_reserved_page (page); + } + +if (pages && s) +pr_info ("Freeing %s memory: %ldK\n" , s,K (pages)); + +return pages; +} +/** * memblock_free - free boot memory allocation * @ptr: starting address of the boot memory allocation
@@ -1776,7 +1812,6 @@ void __init memblock_free_late(phys_addr_t base, phys_addr_t size)totalram_pages_inc (); } } -/* * Remaining API functions */
mm/page_alloc.c +0 -36
@@ -6234,42 +6234,6 @@ void adjust_managed_page_count(struct page *page, long count) }EXPORT_SYMBOL (adjust_managed_page_count); -unsigned long free_reserved_area (void *start,void *end,int poison,const char *s) -{ -void *pos; -unsigned long pages =0 ; - - start = (void *)PAGE_ALIGN ((unsigned long )start); - end = (void *)((unsigned long )end &PAGE_MASK ); -for (pos = start; pos < end; pos +=PAGE_SIZE , pages++) { -struct page *page =virt_to_page (pos); -void *direct_map_addr; - -/* -* 'direct_map_addr' might be different from 'pos' -* because some architectures' virt_to_page() -* work with aliases. Getting the direct map -* address ensures that we get a _writeable_ -* alias for the memset(). -*/ - direct_map_addr =page_address (page); -/* -* Perform a kasan-unchecked memset() since this memory -* has not been initialized. -*/ - direct_map_addr =kasan_reset_tag (direct_map_addr); -if ((unsigned int )poison <=0xFF ) -memset (direct_map_addr, poison,PAGE_SIZE ); - -free_reserved_page (page); - } - -if (pages && s) -pr_info ("Freeing %s memory: %ldK\n" , s,K (pages)); - -return pages; -} -void free_reserved_page (struct page *page) {clear_page_tag_ref (page);
tools/include/linux/mm.h +1 -0
@@ -17,6 +17,7 @@#define __va (x) ((void *)((unsigned long)(x)))#define __pa (x) ((unsigned long)(x)) +#define __pa_symbol (x) ((unsigned long)(x))#define pfn_to_page (pfn) ((void *)((pfn) * PAGE_SIZE))
tools/testing/memblock/internal.h +31 -3
@@ -11,9 +11,22 @@ static int memblock_debug = 1;#define pr_warn_ratelimited (fmt, ...) printf(fmt, ##__VA_ARGS__) +#define K (x) ((x) << (PAGE_SHIFT-10)) +bool mirrored_kernelcore = false;struct page {}; +static inline void *page_address (struct page *page) +{ +BUG (); +return page; +} + +static inline struct page *virt_to_page (void *virt) +{ +BUG (); +return virt; +}void memblock_free_pages (unsigned long pfn,unsigned int order) {
@@ -23,10 +36,25 @@ static inline void accept_memory(phys_addr_t start, unsigned long size) { } -static inline unsigned long free_reserved_area (void *start,void *end, -int poison,const char *s) +unsigned long free_reserved_area (void *start,void *end,int poison,const char *s); +void free_reserved_page (struct page *page); + +static inline bool deferred_pages_enabled (void ) +{ +return false; +} + +#define for_each_valid_pfn (pfn, start_pfn, end_pfn) \ + for ((pfn) = (start_pfn); (pfn) < (end_pfn); (pfn)++) + +static inline void *kasan_reset_tag (const void *addr) +{ +return (void *)addr; +} + +static inline bool __is_kernel (unsigned long addr) { -return 0 ; +return false; }#endif
Signature · 1 line
2.53.0
Re: [PATCH v2 4/9] mm: move free_reserved_area() to mm/memblock.c
Quoted 11 lines · Mike Rapoport
From: "Mike Rapoport (Microsoft)" <[email protected]>
free_reserved_area()is related to memblock as it frees reserved memory back to the buddy allocator, similar to whatmemblock_free_late()does.Move
free_reserved_area()tomm/memblock.cto prepare for further consolidation of the functions that free reserved memory.No functional changes.
Signed-off-by Mike Rapoport (Microsoft) <[email protected]>
Mike Rapoport
maintainerPATCH v2 5/9 memblock: make free_reserved_area() more robust
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
There are two potential problems in free_reserved_area():
* it may free a page with not-existent buddy page
* it may be passed a virtual address from an alias mapping that won't be properly translated by virt_to_page(), for example a symbol on arm64
While first issue is quite theoretical and the second one does not manifest itself because all the callers do the right thing, it is easy to make free_reserved_area() robust enough to avoid these potential issues.
Replace the loop by virtual address with a loop by pfn that uses for_each_valid_pfn() and use __pa() or __pa_symbol() depending on the virtual mapping alias to correctly determine the loop boundaries.
--- mm/memblock.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-)
mm/memblock.c +23 -11
@@ -895,21 +895,32 @@ int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)unsigned long free_reserved_area (void *start,void *end,int poison,const char *s) { -void *pos; -unsigned long pages =0 ; +phys_addr_t start_pa, end_pa; +unsigned long pages =0 , pfn; - start = (void *)PAGE_ALIGN ((unsigned long )start); - end = (void *)((unsigned long )end &PAGE_MASK ); -for (pos = start; pos < end; pos +=PAGE_SIZE , pages++) { -struct page *page =virt_to_page (pos); +/* +* end is the first address past the region and it may be beyond what +* __pa() or __pa_symbol() can handle. +* Use the address included in the range for the conversion and add +* back 1 afterwards. +*/ +if (__is_kernel ((unsigned long )start)) { + start_pa =__pa_symbol (start); + end_pa =__pa_symbol (end -1 ) +1 ; + }else { + start_pa =__pa (start); + end_pa =__pa (end -1 ) +1 ; + } + +for_each_valid_pfn (pfn,PFN_UP (start_pa),PFN_DOWN (end_pa)) { +struct page *page =pfn_to_page (pfn);void *direct_map_addr;/* -* 'direct_map_addr' might be different from 'pos' -* because some architectures' virt_to_page() -* work with aliases. Getting the direct map -* address ensures that we get a _writeable_ -* alias for the memset(). +* 'direct_map_addr' might be different from the kernel virtual +* address because some architectures use aliases. +* Going via physical address, pfn_to_page() and page_address() +* ensures that we get a _writeable_ alias for the memset(). */ direct_map_addr =page_address (page);/*
@@ -921,6 +932,7 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const charmemset (direct_map_addr, poison,PAGE_SIZE );free_reserved_page (page); + pages++; }if (pages && s)
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 6/9 memblock: extract page freeing from free_reserved_area() into a helper
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
There are two functions that release pages to the buddy allocator late in the boot: free_reserved_area() and memblock_free_late().
Currently they are using different underlying functionality, free_reserved_area() runs each page being freed via free_reserved_page() and memblock_free_late() uses memblock_free_pages() -> __free_pages_core(), but in the end they both boil down to a loop that frees a range page by page.
Extract the loop frees pages from free_reserved_area() into a helper and use that helper in memblock_free_late().
--- mm/memblock.c | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-)
mm/memblock.c +29 -26
@@ -893,26 +893,12 @@ int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)return memblock_remove_range (&memblock.memory, base, size); } -unsigned long free_reserved_area (void *start,void *end,int poison,const char *s) +static unsigned long __free_reserved_area (phys_addr_t start,phys_addr_t end, +int poison) { -phys_addr_t start_pa, end_pa;unsigned long pages =0 , pfn; -/* -* end is the first address past the region and it may be beyond what -* __pa() or __pa_symbol() can handle. -* Use the address included in the range for the conversion and add -* back 1 afterwards. -*/ -if (__is_kernel ((unsigned long )start)) { - start_pa =__pa_symbol (start); - end_pa =__pa_symbol (end -1 ) +1 ; - }else { - start_pa =__pa (start); - end_pa =__pa (end -1 ) +1 ; - } - -for_each_valid_pfn (pfn,PFN_UP (start_pa),PFN_DOWN (end_pa)) { +for_each_valid_pfn (pfn,PFN_UP (start),PFN_DOWN (end)) {struct page *page =pfn_to_page (pfn);void *direct_map_addr;
@@ -934,7 +920,29 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const charfree_reserved_page (page); pages++; } +return pages; +} + +unsigned long free_reserved_area (void *start,void *end,int poison,const char *s) +{ +phys_addr_t start_pa, end_pa; +unsigned long pages; + +/* +* end is the first address past the region and it may be beyond what +* __pa() or __pa_symbol() can handle. +* Use the address included in the range for the conversion and add back +* 1 afterwards. +*/ +if (__is_kernel ((unsigned long )start)) { + start_pa =__pa_symbol (start); + end_pa =__pa_symbol (end -1 ) +1 ; + }else { + start_pa =__pa (start); + end_pa =__pa (end -1 ) +1 ; + } + pages =__free_reserved_area (start_pa, end_pa, poison);if (pages && s)pr_info ("Freeing %s memory: %ldK\n" , s,K (pages));
@@ -1810,20 +1818,15 @@ void *__init __memblock_alloc_or_panic(phys_addr_t size, phys_addr_t align,*/ void __init memblock_free_late (phys_addr_t base,phys_addr_t size) { -phys_addr_t cursor, end; +phys_addr_t end = base + size -1 ; - end = base + size -1 ;memblock_dbg ("%s: [%pa-%pa] %pS\n" , __func__, &base, &end, (void *)_RET_IP_); -kmemleak_free_part_phys (base, size); - cursor =PFN_UP (base); - end =PFN_DOWN (base + size); -for (; cursor < end; cursor++) { -memblock_free_pages (cursor,0 ); -totalram_pages_inc (); - } +kmemleak_free_part_phys (base, size); +__free_reserved_area (base, base + size,-1 ); } +/* * Remaining API functions */
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 7/9 memblock: make free_reserved_area() update memblock if ARCH_KEEP_MEMBLOCK=y
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
On architectures that keep memblock after boot, freeing of reserved memory with free_reserved_area() is paired with an update of memblock arrays, usually by a call to memblock_free().
Make free_reserved_area() directly update memblock.reserved when ARCH_KEEP_MEMBLOCK is enabled.
Remove the now-redundant explicit memblock_free() call from arm64::free_initmem() and the #ifdef CONFIG_ARCH_KEEP_MEMBLOCK block from the generic free_initrd_mem().
--- arch/arm64/mm/init.c | 3 --- init/initramfs.c | 7 ------- mm/memblock.c | 6 ++++++ 3 files changed, 6 insertions(+), 10 deletions(-)
arch/arm64/mm/init.c +0 -3
@@ -385,9 +385,6 @@ void free_initmem(void)WARN_ON (!IS_ALIGNED ((unsigned long )lm_init_begin,PAGE_SIZE ));WARN_ON (!IS_ALIGNED ((unsigned long )lm_init_end,PAGE_SIZE )); -/* Delete __init region from memblock.reserved. */ -memblock_free (lm_init_begin, lm_init_end - lm_init_begin); -free_reserved_area (lm_init_begin, lm_init_end,POISON_FREE_INITMEM ,"unused kernel" );/*
init/initramfs.c +0 -7
@@ -652,13 +652,6 @@ void __init reserve_initrd_mem(void)void __weak __init free_initrd_mem (unsigned long start,unsigned long end) { -#ifdef CONFIG_ARCH_KEEP_MEMBLOCK -unsigned long aligned_start =ALIGN_DOWN (start,PAGE_SIZE ); -unsigned long aligned_end =ALIGN (end,PAGE_SIZE ); - -memblock_free ((void *)aligned_start, aligned_end - aligned_start); -#endif -free_reserved_area ((void *)start, (void *)end,POISON_FREE_INITMEM ,"initrd" ); }
mm/memblock.c +6 -0
@@ -942,6 +942,12 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const char end_pa =__pa (end -1 ) +1 ; } +if (IS_ENABLED (CONFIG_ARCH_KEEP_MEMBLOCK )) { +if (start_pa < end_pa) +memblock_remove_range (&memblock.reserved, + start_pa, end_pa - start_pa); + } + pages =__free_reserved_area (start_pa, end_pa, poison);if (pages && s)pr_info ("Freeing %s memory: %ldK\n" , s,K (pages));
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 8/9 memblock, treewide: make memblock_free() handle late freeing
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
It shouldn't be responsibility of memblock users to detect if they free memory allocated from memblock late and should use memblock_free_late().
Make memblock_free() and memblock_phys_free() take care of late memory freeing and drop memblock_free_late().
--- arch/sparc/kernel/mdesc.c | 4 +- arch/x86/kernel/setup.c | 2 +- arch/x86/platform/efi/memmap.c | 5 +-- arch/x86/platform/efi/quirks.c | 2 +- drivers/firmware/efi/apple-properties.c | 2 +- drivers/of/kexec.c | 2 +- include/linux/memblock.h | 2 - kernel/dma/swiotlb.c | 6 +-- lib/bootconfig.c | 2 +- mm/kfence/core.c | 4 +- mm/memblock.c | 49 ++++++++++--------------- 11 files changed, 31 insertions(+), 49 deletions(-)
arch/sparc/kernel/mdesc.c +1 -3
@@ -183,14 +183,12 @@ static struct mdesc_handle * __init mdesc_memblock_alloc(unsigned int mdesc_sizestatic void __init mdesc_memblock_free (struct mdesc_handle *hp) {unsigned int alloc_size; -unsigned long start;BUG_ON (refcount_read (&hp->refcnt) !=0 );BUG_ON (!list_empty (&hp->list)); alloc_size =PAGE_ALIGN (hp->handle_size); - start =__pa (hp); -memblock_free_late (start, alloc_size); +memblock_free (hp, alloc_size); }static struct mdesc_mem_ops memblock_mdesc_ops = {
arch/x86/kernel/setup.c +1 -1
@@ -426,7 +426,7 @@ int __init ima_free_kexec_buffer(void)if (!ima_kexec_buffer_size)return -ENOENT ; -memblock_free_late (ima_kexec_buffer_phys, +memblock_phys_free (ima_kexec_buffer_phys, ima_kexec_buffer_size); ima_kexec_buffer_phys =0 ;
arch/x86/platform/efi/memmap.c +1 -4
@@ -34,10 +34,7 @@ staticvoid __init __efi_memmap_free (u64 phys,unsigned long size,unsigned long flags) {if (flags &EFI_MEMMAP_MEMBLOCK ) { -if (slab_is_available ()) -memblock_free_late (phys, size); -else -memblock_phys_free (phys, size); +memblock_phys_free (phys, size); }else if (flags &EFI_MEMMAP_SLAB ) {struct page *p =pfn_to_page (PHYS_PFN (phys));unsigned int order =get_order (size);
arch/x86/platform/efi/quirks.c +1 -1
@@ -372,7 +372,7 @@ void __init efi_reserve_boot_services(void)* doesn't make sense as far as the firmware is * concerned, but it does provide us with a way to tag * those regions that must not be paired with -* memblock_free_late(). +* memblock_phys_free(). */ md->attribute |=EFI_MEMORY_RUNTIME ; }
drivers/firmware/efi/apple-properties.c +1 -1
@@ -226,7 +226,7 @@ static int __init map_properties(void)*/ data->len =0 ;memunmap (data); -memblock_free_late (pa_data +sizeof (*data), data_len); +memblock_phys_free (pa_data +sizeof (*data), data_len);return ret; }
drivers/of/kexec.c +1 -1
@@ -175,7 +175,7 @@ int __init ima_free_kexec_buffer(void)if (ret)return ret; -memblock_free_late (addr, size); +memblock_phys_free (addr, size); return 0; }#endif
include/linux/memblock.h +0 -2
@@ -172,8 +172,6 @@ void __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid); -void memblock_free_late (phys_addr_t base,phys_addr_t size); -#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP static inline void __next_physmem_range(u64 *idx, struct memblock_type *type, phys_addr_t *out_start,
kernel/dma/swiotlb.c +3 -3
@@ -546,10 +546,10 @@ void __init swiotlb_exit(void)free_pages (tbl_vaddr,get_order (tbl_size));free_pages ((unsigned long )mem->slots,get_order (slots_size)); }else { -memblock_free_late (__pa (mem->areas), +memblock_free (mem->areas,array_size (sizeof (*mem->areas), mem->nareas)); -memblock_free_late (mem->start, tbl_size); -memblock_free_late (__pa (mem->slots), slots_size); +memblock_phys_free (mem->start, tbl_size); +memblock_free (mem->slots, slots_size); }memset (mem,0 ,sizeof (*mem));
lib/bootconfig.c +1 -1
@@ -64,7 +64,7 @@ static inline void __init xbc_free_mem(void *addr, size_t size, bool early)if (early)memblock_free (addr, size);else if (addr) - memblock_free_late(__pa(addr), size); + memblock_free(addr, size); }#else /* !__KERNEL__ */
mm/kfence/core.c +2 -2
@@ -731,10 +731,10 @@ static bool __init kfence_init_pool_early(void)* fails for the first page, and therefore expect addr==__kfence_pool in * most failure cases. */ -memblock_free_late (__pa (addr),KFENCE_POOL_SIZE - (addr - (unsigned long )__kfence_pool)); +memblock_free ((void *)addr,KFENCE_POOL_SIZE - (addr - (unsigned long )__kfence_pool)); __kfence_pool =NULL ; -memblock_free_late (__pa (kfence_metadata_init),KFENCE_METADATA_SIZE ); +memblock_free (kfence_metadata_init,KFENCE_METADATA_SIZE ); kfence_metadata_init =NULL ;return false;
mm/memblock.c +19 -30
95 lines not on this page · raw message
Signature · 1 line
2.53.0
Mike Rapoport
maintainerPATCH v2 9/9 memblock: warn when freeing reserved memory before memory map is initialized
In reply to Mike RapoportFrom: "Mike Rapoport (Microsoft)" <[email protected]>
When CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled, freeing of reserved memory before the memory map is fully initialized in deferred_init_memmap() would cause access to uninitialized struct pages and may crash when accessing spurious list pointers, like was recently discovered during discussion about memory leaks in x86 EFI code [1].
The trace below is from an attempt to call free_reserved_page() before page_alloc_init_late():
[ 0.076840] BUG: unable to handle page fault for address: ffffce1a005a0788 [ 0.078226] #PF: supervisor read access in kernel mode [ 0.078226] #PF: error_code(0x0000) - not-present page [ 0.078226] PGD 0 P4D 0 [ 0.078226] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI [ 0.078226] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.12.68-92.123.amzn2023.x86_64 #1 [ 0.078226] Hardware name: Amazon EC2 t3a.nano/, BIOS 1.0 10/16/2017 [ 0.078226] RIP: 0010:__list_del_entry_valid_or_report+0x32/0xb0 ... [ 0.078226] __free_one_page+0x170/0x520 [ 0.078226] free_pcppages_bulk+0x151/0x1e0 [ 0.078226] free_unref_page_commit+0x263/0x320 [ 0.078226] free_unref_page+0x2c8/0x5b0 [ 0.078226] ? srso_return_thunk+0x5/0x5f [ 0.078226] free_reserved_page+0x1c/0x30 [ 0.078226] memblock_free_late+0x6c/0xc0
Currently there are not many callers of free_reserved_area() and they all appear to be at the right timings.
Still, in order to protect against problematic code moves or additions of new callers add a warning that will inform that reserved pages cannot be freed until the memory map is fully initialized.
[1] https://lore.kernel.org/all/e5d5a1105d90ee1e7fe7eafaed2ed03bbad0c46b.camel@kernel.crashing.org/
--- mm/internal.h | 10 ++++++++++ mm/memblock.c | 5 +++++ mm/page_alloc.c | 10 ---------- 3 files changed, 15 insertions(+), 10 deletions(-)
mm/internal.h +10 -0
@@ -1233,7 +1233,17 @@ static inline void vunmap_range_noflush(unsigned long start, unsigned long end)#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT DECLARE_STATIC_KEY_TRUE (deferred_pages); +static inline bool deferred_pages_enabled (void ) +{ +return static_branch_unlikely (&deferred_pages); +} +bool __init deferred_grow_zone (struct zone *zone,unsigned int order); +#else +static inline bool deferred_pages_enabled (void ) +{ +return false; +}#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ void init_deferred_page (unsigned long pfn,int nid);
mm/memblock.c +5 -0
@@ -899,6 +899,11 @@ static unsigned long __free_reserved_area(phys_addr_t start, phys_addr_t end, {unsigned long pages =0 , pfn; +if (deferred_pages_enabled ()) { +WARN (1 ,"Cannot free reserved memory because of deferred initialization of the memory map" ); +return 0 ; + } +for_each_valid_pfn (pfn,PFN_UP (start),PFN_DOWN (end)) {struct page *page =pfn_to_page (pfn);void *direct_map_addr;
mm/page_alloc.c +0 -10
@@ -331,11 +331,6 @@ int page_group_by_mobility_disabled __read_mostly;*/ DEFINE_STATIC_KEY_TRUE (deferred_pages); -static inline bool deferred_pages_enabled (void ) -{ -return static_branch_unlikely (&deferred_pages); -} -/* * deferred_grow_zone() is __init, but it is called from * get_page_from_freelist() during early boot until deferred_pages permanently
@@ -348,11 +343,6 @@ _deferred_grow_zone(struct zone *zone, unsigned int order) return deferred_grow_zone(zone, order); }#else -static inline bool deferred_pages_enabled (void ) -{ -return false; -} -static inline bool _deferred_grow_zone (struct zone *zone,unsigned int order) {return false;
Signature · 1 line
2.53.0
Warning from free_reserved_area() in next-20260325+
Starting with linux next-20260325 I see the following warning early in the boot process of a machine running debian stable (trixie) (except for the kernel):
[ 0.027118] [ T0] ------------[ cut here ]------------ [ 0.027118] [ T0] Cannot free reserved memory because of deferred initialization of the memory map [ 0.027119] [ T0] WARNING: mm/memblock.c:904 at __free_reserved_area+0xa9/0xc0, CPU#0: swapper/0/0 [ 0.027122] [ T0] Modules linked in: [ 0.027123] [ T0] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.0.0-rc5-next-20260326-master #385 PREEMPT_RT [ 0.027125] [ T0] Hardware name: ASUS System Product Name/ROG STRIX B850-F GAMING WIFI, BIOS 1627 02/05/2026 [ 0.027125] [ T0] RIP: 0010:__free_reserved_area+0xa9/0xc0 [ 0.027126] [ T0] Code: 48 89 df 48 89 ee e8 06 fe ff ff 48 89 c3 48 39 e8 72 a0 5b 4c 89 e8 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8d 3d 97 c2 c6 00 <67> 48 0f b9 3a 45 31 ed eb df 66 66 2e 0f 1f 84 00 00 00 00 00 66 [ 0.027127] [ T0] RSP: 0000:ffffffff9b203e98 EFLAGS: 00010202 [ 0.027128] [ T0] RAX: 0000000e91c00001 RBX: ffffffff9b100c0f RCX: 0000000080000001 [ 0.027128] [ T0] RDX: 00000000000000cc RSI: 0000000e2d42d000 RDI: ffffffff9b32ef60 [ 0.027128] [ T0] RBP: ffff9eeafdd6fbc0 R08: 0000000000000000 R09: 0000000000000001 [ 0.027129] [ T0] R10: 0000000000001000 R11: 8000000000000163 R12: 000000000000006f [ 0.027129] [ T0] R13: 0000000000000000 R14: 0000000000000045 R15: 000000005c8a1000 [ 0.027129] [ T0] FS: 0000000000000000(0000) GS:ffff9eeb21c05000(0000) knlGS:0000000000000000 [ 0.027130] [ T0] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.027130] [ T0] CR2: ffff9ee8ad801000 CR3: 0000000e2ce1e000 CR4: 0000000000f50ef0 [ 0.027131] [ T0] PKRU: 55555554 [ 0.027131] [ T0] Call Trace: [ 0.027132] [ T0] <TASK> [ 0.027132] [ T0] free_reserved_area+0x89/0xd0 [ 0.027133] [ T0] alternative_instructions+0xee/0x110 [ 0.027136] [ T0] arch_cpu_finalize_init+0x10f/0x160 [ 0.027138] [ T0] start_kernel+0x686/0x710 [ 0.027140] [ T0] x86_64_start_reservations+0x24/0x30 [ 0.027141] [ T0] x86_64_start_kernel+0xd4/0xe0 [ 0.027142] [ T0] common_startup_64+0x13e/0x141 [ 0.027143] [ T0] </TASK> [ 0.027144] [ T0] ---[ end trace 0000000000000000 ]---
The Hardware used is this:
$ cat /proc/cpuinfo processor : 0 vendor_id : AuthenticAMD cpu family : 26 model : 68 model name : AMD Ryzen 9 9950X 16-Core Processor stepping : 0 microcode : 0xb404035 cpu MHz : 3607.683 cache size : 1024 KB physical id : 0 siblings : 32 core id : 0 cpu cores : 16 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 16 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr_v2 nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpuid_fault cpb cat_l3 cdp_l3 hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp ibrs_enhanced vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk avx_vnni avx512_bf16 clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif x2avic v_spec_ctrl vnmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect movdiri movdir64b overflow_recov succor smca fsrm avx512_vp2intersect flush_l1d amd_lbr_pmc_freeze bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass srso spectre_v2_user vmscape bogomips : 8599.98 TLB size : 192 4K pages clflush size : 64 cache_alignment : 64 address sizes : 48 bits physical, 48 bits virtual power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]
$ lspci 00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Root Complex 00:00.2 IOMMU: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge IOMMU 00:01.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge 00:01.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge 00:01.2 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge 00:02.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge 00:02.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge GPP Bridge 00:03.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge 00:04.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge 00:08.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Dummy Host Bridge 00:08.1 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Internal GPP Bridge to Bus [C:A] 00:08.3 PCI bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Internal GPP Bridge to Bus [C:A] 00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 71) 00:14.3 ISA bridge: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge (rev 51) 00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 0 00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 1 00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 2 00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 3 00:18.4 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 4 00:18.5 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 5 00:18.6 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 6 00:18.7 Host bridge: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge Data Fabric; Function 7 01:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Upstream Port of PCI Express Switch (rev 25) 02:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD/ATI] Navi 10 XL Downstream Port of PCI Express Switch (rev 25) 03:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Navi 44 [RX 9060 XT] (rev c0) 03:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Navi 48 HDMI/DP Audio Controller 04:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD 9100 PRO [PM9E1] 05:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Upstream Port (rev 01) 06:00.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 06:06.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 06:07.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 06:08.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 06:0c.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 06:0d.0 PCI bridge: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset PCIe Switch Downstream Port (rev 01) 08:00.0 Ethernet controller: Intel Corporation Ethernet Controller I226-V (rev 06) 09:00.0 Network controller: MEDIATEK Corp. Device 7925 0b:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] 800 Series Chipset USB 3.x XHCI Controller (rev 01) 0c:00.0 SATA controller: Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller (rev 01) 0d:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge PCIe Dummy Function (rev c1) 0d:00.2 Encryption controller: Advanced Micro Devices, Inc. [AMD] Family 19h PSP/CCP 0d:00.3 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 3.1 xHCI 0d:00.4 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 3.1 xHCI 0e:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] Raphael/Granite Ridge USB 2.0 xHCI
Memory used is 64G:
$ LANG=C free
total used free shared buff/cache available
Mem: 65500068 3584080 56709424 70916 5912256 61915988
Swap: 78125052 0 78125052Bert Karwatzki
Mike Rapoport
maintainerRe: Warning from free_reserved_area() in next-20260325+
Hi Bert,
Quoted 2 lines · Bert Karwatzki
Starting with linux next-20260325 I see the following warning early in the boot process of a machine running debian stable (trixie) (except for the kernel):
Thanks for the report!
Quoted 21 lines
[ 0.027118] [ T0] ------------[ cut here ]------------ [ 0.027118] [ T0] Cannot free reserved memory because of deferred initialization of the memory map [ 0.027119] [ T0] WARNING: mm/memblock.c:904 at __free_reserved_area+0xa9/0xc0, CPU#0: swapper/0/0 [ 0.027122] [ T0] Modules linked in: [ 0.027123] [ T0] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.0.0-rc5-next-20260326-master #385 PREEMPT_RT [ 0.027125] [ T0] Hardware name: ASUS System Product Name/ROG STRIX B850-F GAMING WIFI, BIOS 1627 02/05/2026 [ 0.027125] [ T0] RIP: 0010:__free_reserved_area+0xa9/0xc0 [ 0.027126] [ T0] Code: 48 89 df 48 89 ee e8 06 fe ff ff 48 89 c3 48 39 e8 72 a0 5b 4c 89 e8 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8d 3d 97 c2 c6 00 <67> 48 0f b9 3a 45 31 ed eb df 66 66 2e 0f 1f 84 00 00 00 00 00 66 [ 0.027127] [ T0] RSP: 0000:ffffffff9b203e98 EFLAGS: 00010202 [ 0.027128] [ T0] RAX: 0000000e91c00001 RBX: ffffffff9b100c0f RCX: 0000000080000001 [ 0.027128] [ T0] RDX: 00000000000000cc RSI: 0000000e2d42d000 RDI: ffffffff9b32ef60 [ 0.027128] [ T0] RBP: ffff9eeafdd6fbc0 R08: 0000000000000000 R09: 0000000000000001 [ 0.027129] [ T0] R10: 0000000000001000 R11: 8000000000000163 R12: 000000000000006f [ 0.027129] [ T0] R13: 0000000000000000 R14: 0000000000000045 R15: 000000005c8a1000 [ 0.027129] [ T0] FS: 0000000000000000(0000) GS:ffff9eeb21c05000(0000) knlGS:0000000000000000 [ 0.027130] [ T0] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.027130] [ T0] CR2: ffff9ee8ad801000 CR3: 0000000e2ce1e000 CR4: 0000000000f50ef0 [ 0.027131] [ T0] PKRU: 55555554 [ 0.027131] [ T0] Call Trace: [ 0.027132] [ T0] <TASK> [ 0.027132] [ T0] free_reserved_area+0x89/0xd0
Quoted 8 lines
[ 0.027133] [ T0] alternative_instructions+0xee/0x110 [ 0.027136] [ T0] arch_cpu_finalize_init+0x10f/0x160 [ 0.027138] [ T0] start_kernel+0x686/0x710 [ 0.027140] [ T0] x86_64_start_reservations+0x24/0x30 [ 0.027141] [ T0] x86_64_start_kernel+0xd4/0xe0 [ 0.027142] [ T0] common_startup_64+0x13e/0x141 [ 0.027143] [ T0] </TASK> [ 0.027144] [ T0] ---[ end trace 0000000000000000 ]---
Does this patch fix it for you?
arch/x86/kernel/alternative.c +17 -5
@@ -2448,19 +2448,31 @@ void __init alternative_instructions(void) __smp_locks, __smp_locks_end, _text, _etext); } +#endif +restart_nmi (); + alternatives_patched =1 ; + +alt_reloc_selftest (); +} + +#ifdef CONFIG_SMP +/* +* With CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled we can free_init_pages() only +* after the deferred initialization of the memory map is complete. +*/ +static int __init free_smp_locks (void ) +{if (!uniproc_patched ||num_possible_cpus () ==1 ) {free_init_pages ("SMP alternatives" , (unsigned long )__smp_locks, (unsigned long )__smp_locks_end); } -#endif -restart_nmi (); - alternatives_patched =1 ; - -alt_reloc_selftest (); +return 0 ; } +arch_initcall (free_smp_locks); +#endif /** * text_poke_early - Update instructions on a live kernel at boot time
Quoted 1 line
Bert Karwatzki
Signature · 2 lines
Sincerely yours, Mike.
Bert Karwatzki
Tested-byRe: Warning from free_reserved_area() in next-20260325+
Am Freitag, dem 27.03.2026 um 20:12 +0300 schrieb Mike Rapoport:
Quoted 82 lines
Hi Bert,
Quoted 2 lines · Bert Karwatzki
Starting with linux next-20260325 I see the following warning early in the boot process of a machine running debian stable (trixie) (except for the kernel):
Thanks for the report!
Quoted 21 lines
[ 0.027118] [ T0] ------------[ cut here ]------------ [ 0.027118] [ T0] Cannot free reserved memory because of deferred initialization of the memory map [ 0.027119] [ T0] WARNING: mm/memblock.c:904 at __free_reserved_area+0xa9/0xc0, CPU#0: swapper/0/0 [ 0.027122] [ T0] Modules linked in: [ 0.027123] [ T0] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.0.0-rc5-next-20260326-master #385 PREEMPT_RT [ 0.027125] [ T0] Hardware name: ASUS System Product Name/ROG STRIX B850-F GAMING WIFI, BIOS 1627 02/05/2026 [ 0.027125] [ T0] RIP: 0010:__free_reserved_area+0xa9/0xc0 [ 0.027126] [ T0] Code: 48 89 df 48 89 ee e8 06 fe ff ff 48 89 c3 48 39 e8 72 a0 5b 4c 89 e8 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8d 3d 97 c2 c6 00 <67> 48 0f b9 3a 45 31 ed eb df 66 66 2e 0f 1f 84 00 00 00 00 00 66 [ 0.027127] [ T0] RSP: 0000:ffffffff9b203e98 EFLAGS: 00010202 [ 0.027128] [ T0] RAX: 0000000e91c00001 RBX: ffffffff9b100c0f RCX: 0000000080000001 [ 0.027128] [ T0] RDX: 00000000000000cc RSI: 0000000e2d42d000 RDI: ffffffff9b32ef60 [ 0.027128] [ T0] RBP: ffff9eeafdd6fbc0 R08: 0000000000000000 R09: 0000000000000001 [ 0.027129] [ T0] R10: 0000000000001000 R11: 8000000000000163 R12: 000000000000006f [ 0.027129] [ T0] R13: 0000000000000000 R14: 0000000000000045 R15: 000000005c8a1000 [ 0.027129] [ T0] FS: 0000000000000000(0000) GS:ffff9eeb21c05000(0000) knlGS:0000000000000000 [ 0.027130] [ T0] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.027130] [ T0] CR2: ffff9ee8ad801000 CR3: 0000000e2ce1e000 CR4: 0000000000f50ef0 [ 0.027131] [ T0] PKRU: 55555554 [ 0.027131] [ T0] Call Trace: [ 0.027132] [ T0] <TASK> [ 0.027132] [ T0] free_reserved_area+0x89/0xd0Quoted 8 lines
[ 0.027133] [ T0] alternative_instructions+0xee/0x110 [ 0.027136] [ T0] arch_cpu_finalize_init+0x10f/0x160 [ 0.027138] [ T0] start_kernel+0x686/0x710 [ 0.027140] [ T0] x86_64_start_reservations+0x24/0x30 [ 0.027141] [ T0] x86_64_start_kernel+0xd4/0xe0 [ 0.027142] [ T0] common_startup_64+0x13e/0x141 [ 0.027143] [ T0] </TASK> [ 0.027144] [ T0] ---[ end trace 0000000000000000 ]---Does this patch fix it for you?
arch/x86/kernel/alternative.c +17
-5@@ -2448,19 +2448,31 @@ void __init alternative_instructions(void) __smp_locks, __smp_locks_end, _text, _etext); } +#endif +restart_nmi (); + alternatives_patched =1 ; + +alt_reloc_selftest (); +} + +#ifdef CONFIG_SMP +/* +* With CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled we can free_init_pages() only +* after the deferred initialization of the memory map is complete. +*/ +static int __init free_smp_locks (void ) +{if (!uniproc_patched ||num_possible_cpus () ==1 ) {free_init_pages ("SMP alternatives" , (unsigned long )__smp_locks, (unsigned long )__smp_locks_end); } -#endif -restart_nmi (); - alternatives_patched =1 ; - -alt_reloc_selftest (); +return 0 ; } +arch_initcall (free_smp_locks); +#endif /** * text_poke_early - Update instructions on a live kernel at boot time
Quoted 1 line
Quoted 1 line
Bert Karwatzki
Yes, your patch fixes the issue in next-20260326.
Bert Karwatzki
Quoted 9 lines · Mike Rapoport
From: "Mike Rapoport (Microsoft)" <[email protected]>
Hi,
Following a recent discussion about leaks in x86 EFI [1], I audited usage of
memblock_free_late()andfree_reserved_area()and made some imporovements how we handle late freeing of the memory allocated with memblock.[...]
Applied to for-next branch of memblock.git tree, thanks!
[1/9] memblock: reserve_mem: fix end caclulation in reserve_mem_release_by_name()
commit: ea459d3c24fefd90b60a702f4a73833434ae0248
[2/9] powerpc: fadump: pair alloc_pages_exact() with free_pages_exact()
commit: 6e827110aea5fb9c53a5bf070413ffe5cad105b0
[3/9] powerpc: opal-core: pair alloc_pages_exact() with free_pages_exact()
commit: 3cf80188ecb828ed034ba562614cf1d48156b126
[4/9] mm: move free_reserved_area() to mm/memblock.c
commit: 0aa264cda784f9fbe1a80ef13144cf81610086c7
[5/9] memblock: make free_reserved_area() more robust
commit: 456ac994018598bc57ceaacb8a2c72e722c9755b
[6/9] memblock: extract page freeing from free_reserved_area() into a helper
commit: 40191dae9ed84c816b593bb1b36a80f86c2279d1
[7/9] memblock: make free_reserved_area() update memblock if ARCH_KEEP_MEMBLOCK=y
commit: b9e028ca869de24df00206d7ec640380670fc38f
[8/9] memblock, treewide: make memblock_free() handle late freeing
commit: 64cb853c2ab4d8bd25b965f05e33ac0c6672bae7
[9/9] memblock: warn when freeing reserved memory before memory map is initialized
commit: c7fc9cde41be029cf6675befbafcbb2dab40b39btree: https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock
branch: for-next
--
Sincerely yours,
Mike.