From e349b24573870ef50d0c1b3bf124e14f5dfe1fa5 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 21 Nov 2022 13:36:59 -0500 Subject: [PATCH] mm/thp: Wr-protect pte after mkdirty Content-type: text/plain Anatoly Pugachev reported sparc64 breakage on the patch: https://lore.kernel.org/r/20221021160603.GA23307@u164.east.ru Hev also reported similar issue on loongarch: (the original mail was private, but Anatoly copied the list here) https://lore.kernel.org/r/CADxRZqxqb7f_WhMh=jweZP+ynf_JwGd-0VwbYgp4P+T0-AXosw@mail.gmail.com Also Hev pointed out that the issue is having HW write bit set within the pte_mkdirty() so the split pte can be written after split even if e.g. they were shared by more than one processes, causing data corrupt. Hev also tried to explain why loongarch set HW write bit in mkdirty: https://lore.kernel.org/r/CAHirt9itKO_K_HPboXh5AyJtt16Zf0cD73PtHvM=na39u_ztxA@mail.gmail.com One way to fix it is as what Huacai proposed here for loongarch: https://lore.kernel.org/r/20221117042532.4064448-1-chenhuacai@loongson.cnn Or more agressively, not sure whether (IMHO) we can remove the "optimization" to grant HW write bit in pte_mkdirty() in both archs, leaving set the write bit only in pte_mkwrite(). For now the simpler solution that'll work for all is we wr-protect after pte_mkdirty(), so the HW write bit can be persistent after thp split. Cc: Hev Cc: Andrew Morton Reported-by: Anatoly Pugachev Signed-off-by: Peter Xu --- mm/huge_memory.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index e5f5a1a00596..ae90b65f6121 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2191,13 +2191,18 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, entry = maybe_mkwrite(entry, vma); if (anon_exclusive) SetPageAnonExclusive(page + i); - if (!write) - entry = pte_wrprotect(entry); if (!young) entry = pte_mkold(entry); /* NOTE: this may set soft-dirty too on some archs */ if (dirty) entry = pte_mkdirty(entry); + /* + * NOTE: this needs to happen after pte_mkdirty, + * because some archs (sparc64, loongarch) could + * set hw write bit when mkdirty. + */ + if (!write) + entry = pte_wrprotect(entry); if (soft_dirty) entry = pte_mksoft_dirty(entry); if (uffd_wp) -- 2.37.3