On s390, memory blocks are not currently removed via arch_remove_memory(). With upcoming dynamic memory (de)configuration support, runtime removal of memory blocks is possible. This internally involves tearing down identity mapping, virtual memory mappings and freeing the physical memory backing the struct pages metadata. During early boot, physical memory used to back the struct pages metadata in vmemmap is allocated through: setup_arch() -> sparse_init() -> sparse_init_nid() -> __populate_section_memmap() -> vmemmap_alloc_block_buf() -> sparse_buffer_alloc() -> memblock_alloc() Here, sparse_init_nid() sets up virtual-to-physical mapping for struct pages backed by memblock_alloc(). This differs from runtime addition of hotplug memory which uses the buddy allocator later. To correctly free identity mappings, vmemmap mappings during hot-remove, boot-time and runtime allocations must be distinguished using the PageReserved bit: * Boot-time memory, such as identity-mapped page tables allocated via boot_crst_alloc() and reserved via reserve_pgtables() is marked PageReserved in memmap_init_reserved_pages(). * Physical memory backing vmemmap (struct pages from memblock_alloc()) is also marked PageReserved similarly. During teardown, PageReserved bit is checked to distinguish between boot-time allocation or buddy allocation. This is similar to commit 645d5ce2f7d6 ("powerpc/mm/radix: Fix PTE/PMD fragment count for early page table mappings") Reviewed-by: Heiko Carstens Signed-off-by: Sumanth Korikkar --- arch/s390/mm/pgalloc.c | 2 ++ arch/s390/mm/vmem.c | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index ad3e0f7f7fc1..596c05244ed0 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -164,6 +164,8 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) { struct ptdesc *ptdesc = virt_to_ptdesc(table); + if (pagetable_is_reserved(ptdesc)) + return free_reserved_ptdesc(ptdesc); pagetable_dtor_free(ptdesc); } diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index f48ef361bc83..d96587b84e81 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -39,15 +40,21 @@ static void __ref *vmem_alloc_pages(unsigned int order) static void vmem_free_pages(unsigned long addr, int order, struct vmem_altmap *altmap) { + unsigned int nr_pages = 1 << order; + struct page *page; + if (altmap) { vmem_altmap_free(altmap, 1 << order); return; } - /* We don't expect boot memory to be removed ever. */ - if (!slab_is_available() || - WARN_ON_ONCE(PageReserved(virt_to_page((void *)addr)))) - return; - free_pages(addr, order); + page = virt_to_page((void *)addr); + if (PageReserved(page)) { + /* allocated from memblock */ + while (nr_pages--) + free_bootmem_page(page++); + } else { + free_pages(addr, order); + } } void *vmem_crst_alloc(unsigned long val) @@ -79,10 +86,6 @@ pte_t __ref *vmem_pte_alloc(void) static void vmem_pte_free(unsigned long *table) { - /* We don't expect boot memory to be removed ever. */ - if (!slab_is_available() || - WARN_ON_ONCE(PageReserved(virt_to_page(table)))) - return; page_table_free(&init_mm, table); } -- 2.48.1