]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/sparse-vmemmap: flush_cache_vmap() after hotplugging vmemmap
authorVivian Wang <wangruikang@iscas.ac.cn>
Mon, 13 Jul 2026 17:29:52 +0000 (11:29 -0600)
committerPaul Walmsley <pjw@kernel.org>
Mon, 13 Jul 2026 17:29:52 +0000 (11:29 -0600)
section_activate() does not flush TLB after populating new vmemmap
pages. On most architectures, this is okay. However it is a problem on
RISC-V since there the TLB caching non-present entries is permitted,
which causes spurious faults on some hardwares.

This seems to be most easily reproduced with DEBUG_VM=y and
PAGE_POISONING=y, which causes these newly mapped struct pages to be
poisoned i.e. written to immediately after mapping.

Extend the RISC-V flush_cache_vmap() to also handle the vmemmap range,
and call it after hotplugging vmemmap, which gets the possible spurious
fault handled in the exception handler.

At least for now, the only other architecture with both
SPARSEMEM_VMEMMAP and flush_cache_vmap() is PowerPC, which has a similar
problem with newly valid PTEs. But there flush_cache_vmap() is just a
ptesync. So it should be safe to do this for generic code while having
minimal performance impact.

Suggested-by: Muchun Song <muchun.song@linux.dev>
Signed-off-by: Vivian Wang <wangruikang@iscas.ac.cn>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Link: https://patch.msgid.link/20260713-mark-after-vmemmap-populate-v6-2-b945ceba29d4@iscas.ac.cn
Signed-off-by: Paul Walmsley <pjw@kernel.org>
arch/riscv/include/asm/cacheflush.h
mm/sparse-vmemmap.c

index 58e787fad029fd646e544a93b664202363fa87c5..c2b0a2928f06743e59485e165b9edf976b84212e 100644 (file)
@@ -56,7 +56,8 @@ static inline void mark_new_valid_map(void)
 #define flush_cache_vmap flush_cache_vmap
 static inline void flush_cache_vmap(unsigned long start, unsigned long end)
 {
-       if (is_vmalloc_or_module_addr((void *)start))
+       if (is_vmalloc_or_module_addr((void *)start) ||
+           (start >= VMEMMAP_START && end <= VMEMMAP_END))
                mark_new_valid_map();
 }
 #define flush_cache_vmap_early(start, end)     local_flush_tlb_kernel_range(start, end)
index 99e2be39671b63da971f36f07edb3af1df51d3d2..ebd3ac997f645b8ea3d5ad5088887a93343a28d8 100644 (file)
@@ -564,6 +564,8 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn,
        if (r < 0)
                return NULL;
 
+       flush_cache_vmap(start, end);
+
        return pfn_to_page(pfn);
 }