Skip to content

Commit 4f43ade

Browse files
committed
Merge tag 'fixes-2023-01-14' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock
Pull memblock fix from Mike Rapoport: "memblock: always release pages to the buddy allocator in memblock_free_late() If CONFIG_DEFERRED_STRUCT_PAGE_INIT is enabled, memblock_free_pages() only releases pages to the buddy allocator if they are not in the deferred range. This is correct for free pages (as defined by for_each_free_mem_pfn_range_in_zone()) because free pages in the deferred range will be initialized and released as part of the deferred init process. memblock_free_pages() is called by memblock_free_late(), which is used to free reserved ranges after memblock_free_all() has run. All pages in reserved ranges have been initialized at that point, and accordingly, those pages are not touched by the deferred init process. This means that currently, if the pages that memblock_free_late() intends to release are in the deferred range, they will never be released to the buddy allocator. They will forever be reserved. In addition, memblock_free_pages() calls kmsan_memblock_free_pages(), which is also correct for free pages but is not correct for reserved pages. KMSAN metadata for reserved pages is initialized by kmsan_init_shadow(), which runs shortly before memblock_free_all(). For both of these reasons, memblock_free_pages() should only be called for free pages, and memblock_free_late() should call __free_pages_core() directly instead. One case where this issue can occur in the wild is EFI boot on x86_64. The x86 EFI code reserves all EFI boot services memory ranges via memblock_reserve() and frees them later via memblock_free_late() (efi_reserve_boot_services() and efi_free_boot_services(), respectively). If any of those ranges happens to fall within the deferred init range, the pages will not be released and that memory will be unavailable. For example, on an Amazon EC2 t3.micro VM (1 GB) booting via EFI: v6.2-rc2: Node 0, zone DMA spanned 4095 present 3999 managed 3840 Node 0, zone DMA32 spanned 246652 present 245868 managed 178867 v6.2-rc2 + patch: Node 0, zone DMA spanned 4095 present 3999 managed 3840 Node 0, zone DMA32 spanned 246652 present 245868 managed 222816 # +43,949 pages" * tag 'fixes-2023-01-14' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock: mm: Always release pages to the buddy allocator in memblock_free_late().
2 parents 880ca43 + 115d9d7 commit 4f43ade

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

mm/memblock.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,13 @@ void __init memblock_free_late(phys_addr_t base, phys_addr_t size)
16401640
end = PFN_DOWN(base + size);
16411641

16421642
for (; cursor < end; cursor++) {
1643-
memblock_free_pages(pfn_to_page(cursor), cursor, 0);
1643+
/*
1644+
* Reserved pages are always initialized by the end of
1645+
* memblock_free_all() (by memmap_init() and, if deferred
1646+
* initialization is enabled, memmap_init_reserved_pages()), so
1647+
* these pages can be released directly to the buddy allocator.
1648+
*/
1649+
__free_pages_core(pfn_to_page(cursor), 0);
16441650
totalram_pages_inc();
16451651
}
16461652
}

tools/testing/memblock/internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ bool mirrored_kernelcore = false;
1515

1616
struct page {};
1717

18+
void __free_pages_core(struct page *page, unsigned int order)
19+
{
20+
}
21+
1822
void memblock_free_pages(struct page *page, unsigned long pfn,
1923
unsigned int order)
2024
{

0 commit comments

Comments
 (0)