[PATCH v2] x86/mm: Clear PUD/PMD entries when splitting huge pages

Phineas Su posted 1 patch 3 days, 5 hours ago
arch/x86/mm/init_64.c | 2 ++
1 file changed, 2 insertions(+)
[PATCH v2] x86/mm: Clear PUD/PMD entries when splitting huge pages
Posted by Phineas Su 3 days, 5 hours ago
When phys_pud_init() or phys_pmd_init() splits an existing huge page
(pud_leaf(*pud) or pmd_leaf(*pmd)) into lower-level table entries, it
extracts the page protection attributes but does not clear the existing
PUD/PMD entry (*pud or *pmd).

Subsequently, set_pud_safe() / set_pmd_safe() is invoked to link the new
PMD/PTE table. Because *pud / *pmd is still populated with the huge page
entry, set_pud_safe() / set_pmd_safe() detects a present entry that differs
from the new table pointer, triggering a WARN_ON_ONCE call trace:

  WARNING: CPU: 0 PID: 0 at arch/x86/mm/init_64.c:89 phys_pud_init+0x2d6/0x390

Call pud_clear(pud) and pmd_clear(pmd) right after extracting protection
attributes when splitting 1 GB / 2 MB huge pages so that set_pud_safe() and
set_pmd_safe() can populate lower-level tables cleanly without issuing a
warning.

Signed-off-by: Phineas Su <pohaosu@google.com>
---
v2:
 - Also add pmd_clear(pmd) in phys_pmd_init() to handle 2 MB huge page splitting.
 - Update commit message to cover both PUD and PMD splitting.

arch/x86/mm/init_64.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index d57f29ca23a5..55845c40c1ca 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -573,6 +573,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
 				continue;
 			}
 			new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
+			pmd_clear(pmd);
 		}
 
 		if (page_size_mask & (1<<PG_LEVEL_2M)) {
@@ -659,6 +660,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
 				continue;
 			}
 			prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
+			pud_clear(pud);
 		}
 
 		if (page_size_mask & (1<<PG_LEVEL_1G)) {
-- 
2.55.0.229.g6434b31f56-goog