When vmemmap or usemap allocation fails, sparse_init_nid() currently marks the section non-present and continues. Later boot-time code can still walk PFNs in that section without checking for this partial setup, which leads to invalid accesses. subsection_map_init() can also touch an unallocated usemap.
Auditing and fixing all early PFN walkers for this case is not worth the complexity. These allocation failures are expected to be fatal anyway, and other memory models already treat them that way. Make memmap and usemap allocation failures panic immediately instead of trying to recover and crashing later in less obvious ways. This is also consistent with how other memory model configurations handle memmap allocation failures. Signed-off-by: Muchun Song <[email protected]> Acked-by: Mike Rapoport (Microsoft) <[email protected]> --- v1->v2: - Add Acked-by from Mike Rapoport - I refrained from adding panic() to memmap_alloc() as it wouldn't simplify the code. However, panic() is still required in sparse_init_nid() because the architecture-specific vmemmap_populate() bypasses memmap_alloc(). --- mm/sparse.c | 44 +++++++++----------------------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/mm/sparse.c b/mm/sparse.c index 16ac6df3c89f..c92bbc3f3aa3 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -239,15 +239,8 @@ struct page __init *__populate_section_memmap(unsigned long pfn, struct dev_pagemap *pgmap) { unsigned long size = section_map_size(); - struct page *map; - phys_addr_t addr = __pa(MAX_DMA_ADDRESS); - map = memmap_alloc(size, size, addr, nid, false); - if (!map) - panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%pa\n", - __func__, size, PAGE_SIZE, nid, &addr); - - return map; + return memmap_alloc(size, size, __pa(MAX_DMA_ADDRESS), nid, false); } #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ @@ -300,17 +293,14 @@ static void __init sparse_init_nid(int nid, unsigned long pnum_begin, unsigned long map_count) { unsigned long pnum; - struct page *map; - struct mem_section *ms; - if (sparse_usage_init(nid, map_count)) { - pr_err("%s: node[%d] usemap allocation failed", __func__, nid); - goto failed; - } + if (sparse_usage_init(nid, map_count)) + panic("Failed to allocate usemap for node %d\n", nid); sparse_vmemmap_init_nid_early(nid); for_each_present_section_nr(pnum_begin, pnum) { + struct mem_section *ms; unsigned long pfn = section_nr_to_pfn(pnum); if (pnum >= pnum_end) @@ -318,34 +308,18 @@ static void __init sparse_init_nid(int nid, unsigned long pnum_begin, ms = __nr_to_section(pnum); if (!preinited_vmemmap_section(ms)) { + struct page *map; + map = __populate_section_memmap(pfn, PAGES_PER_SECTION, - nid, NULL, NULL); - if (!map) { - pr_err("%s: node[%d] memory map backing failed. Some memory will not be available.", - __func__, nid); - pnum_begin = pnum; - sparse_usage_fini(); - goto failed; - } + nid, NULL, NULL); + if (!map) + panic("Failed to allocate memmap for section %lu\n", pnum); memmap_boot_pages_add(DIV_ROUND_UP(PAGES_PER_SECTION * sizeof(struct page), PAGE_SIZE)); sparse_init_early_section(nid, map, pnum, 0); } } sparse_usage_fini(); - return; -failed: - /* - * We failed to allocate, mark all the following pnums as not present, - * except the ones already initialized earlier. - */ - for_each_present_section_nr(pnum_begin, pnum) { - if (pnum >= pnum_end) - break; - ms = __nr_to_section(pnum); - if (!preinited_vmemmap_section(ms)) - ms->section_mem_map = 0; - } } /* -- 2.54.0
