From: Quanmin Yan <yanquanmin1@huawei.com> hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9667 ------------------------ In vmemmap_should_optimize(), pmdp is calculated using vaddr and then used to obtain vmemmap_page. Because no lock is held during this process, an abnormal value of *pmdp is read when there are concurrent scenarios on ARM64: CPU 1 CPU 2 ------------------------ ----------------------------- vmemmap_update_pmd() vmemmap_should_optimize() ... ... pmdp = pmd_off_k(vaddr) pmd_clear(pmdp) (clear the same pmdp) ... pmd = READ_ONCE(*pmdp) (*pmdp is incorrect value) ... pte_page(*pte_offset_kernel(pmdp, vaddr)) pmd_populate_kernel() In the mainline patch be035a2acf1fa03caf77daff7d8a424f395cfb4c ("mm: hugetlb_vmemmap: move PageVmemmapSelfHosted() check to split_vmemmap_huge_pmd()"), the check for PageVmemmapSelfHosted() was moved into the locked section of vmemmap_pmd_entry(), preventing similar issues. To resolve the current single-point issue, we do not need to backport this highly conflict-prone patch. Instead, add vmemmap_split_lock to prevent concurrent modification of *pmdp by split_vmemmap_huge_pmd(). Fixes: 66361095129b ("mm: memory_hotplug: make hugetlb_optimize_vmemmap compatible with memmap_on_memory") Signed-off-by: Quanmin Yan <yanquanmin1@huawei.com> Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- mm/hugetlb_vmemmap.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c index c197a609b342..3e9c2068a7b9 100644 --- a/mm/hugetlb_vmemmap.c +++ b/mm/hugetlb_vmemmap.c @@ -545,6 +545,13 @@ static bool vmemmap_should_optimize(const struct hstate *h, const struct page *h * vmemmap page. */ pmdp = pmd_off_k(vaddr); +#ifdef CONFIG_ARM64 + /* + * Add lock to prevent concurrent modification of *pmdp by + * split_vmemmap_huge_pmd() as described above. + */ + vmemmap_split_lock(&init_mm.page_table_lock); +#endif /* * The READ_ONCE() is used to stabilize *pmdp in a register or * on the stack so that it will stop changing under the code. @@ -557,6 +564,9 @@ static bool vmemmap_should_optimize(const struct hstate *h, const struct page *h vmemmap_page = pmd_page(pmd) + pte_index(vaddr); else vmemmap_page = pte_page(*pte_offset_kernel(pmdp, vaddr)); +#ifdef CONFIG_ARM64 + vmemmap_split_unlock(&init_mm.page_table_lock); +#endif /* * Due to HugeTLB alignment requirements and the vmemmap pages * being at the start of the hotplugged memory region in -- 2.43.0