Skip to contentSkip to conversation

mm/pgtable: Support for page table check on s390

PATCH In review Alexander Gordeev 5 participants 11 messages Mar 6 – Mar 12

Subsystems (8)
Memory management x86 PowerPC RISC-V +4 more subsystems
lore
Share & tools
lore

Alexander Gordeev

author maintainer
#0 lore raw

Hi All,

In v7.0-rc1 page table check support for PPC was added, which conflicted with this series v1. Thus the only change in v2 is PPC headers update, which still is NOP for non-s390.

I only did compile test for PPC.

Thanks!

Alexander Gordeev (2):
s390/pgtable: Use set_pmd_bit() to invalidate PMD entry
s390: Enable page table check for debug_defconfig

Tobias Huschle (2):
mm/page_table_check: Pass mm_struct to pxx_user_accessible_page() s390/pgtable: Add s390 support for page table check

 arch/arm64/include/asm/pgtable.h             |  6 +-
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 ++--
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 +-
 arch/riscv/include/asm/pgtable.h             |  6 +-
 arch/s390/Kconfig                            |  1 +
 arch/s390/configs/debug_defconfig            |  2 +
 arch/s390/include/asm/pgtable.h              | 60 +++++++++++++++++---
 arch/x86/include/asm/pgtable.h               |  6 +-
 mm/page_table_check.c                        | 15 ++---
 11 files changed, 80 insertions(+), 34 deletions(-)
Signature · 1 line
2.51.0
author maintainer
#1 lore raw

PATCH v2 1/4 mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

[[email protected]: rephrased commit message, removed braces]

---
 arch/arm64/include/asm/pgtable.h             |  6 +++---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 ++--
 arch/riscv/include/asm/pgtable.h             |  6 +++---
 arch/x86/include/asm/pgtable.h               |  6 +++---
 mm/page_table_check.c                        | 15 ++++++---------
 8 files changed, 24 insertions(+), 27 deletions(-)
arch/arm64/include/asm/pgtable.h +3 -3
index b3e58735c49b..ccf0e0638767 100644
@@ -1263,17 +1263,17 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
 #endif
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
 {
 	return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
 }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
 {
 	return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
 }
arch/powerpc/include/asm/book3s/32/pgtable.h +1 -1
index 001e28f9eabc..75195bb44d06 100644
@@ -438,7 +438,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return true;
 }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return pte_present(pte) && !is_kernel_addr(addr);
 }
arch/powerpc/include/asm/book3s/64/pgtable.h +5 -5
index 1a91762b455d..a56df313b585 100644
@@ -549,7 +549,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return arch_pte_access_permitted(pte_val(pte), write, 0);
 }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return pte_present(pte) && pte_user(pte);
 }
@@ -925,9 +925,9 @@ static inline bool pud_access_permitted(pud_t pud, bool write)
 }
 
 #define pud_user_accessible_page pud_user_accessible_page
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
 {
-	return pud_leaf(pud) && pte_user_accessible_page(pud_pte(pud), addr);
+	return pud_leaf(pud) && pte_user_accessible_page(mm, addr, pud_pte(pud));
 }
 
 #define __p4d_raw(x)	((p4d_t) { __pgd_raw(x) })
@@ -1096,9 +1096,9 @@ static inline bool pmd_access_permitted(pmd_t pmd, bool write)
 }
 
 #define pmd_user_accessible_page pmd_user_accessible_page
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
 {
-	return pmd_leaf(pmd) && pte_user_accessible_page(pmd_pte(pmd), addr);
+	return pmd_leaf(pmd) && pte_user_accessible_page(mm, addr, pmd_pte(pmd));
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
arch/powerpc/include/asm/nohash/pgtable.h +1 -1
index e6da5eaccff6..0665d0abe89f 100644
@@ -249,7 +249,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
 	return true;
 }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return pte_present(pte) && !is_kernel_addr(addr);
 }
arch/powerpc/include/asm/pgtable.h +2 -2
index dcd3a88caaf6..29ed509cd235 100644
@@ -205,11 +205,11 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
 #endif /* CONFIG_PPC64 */
 
 #ifndef pmd_user_accessible_page
-#define pmd_user_accessible_page(pmd, addr)	false
+#define pmd_user_accessible_page(mm, addr, pmd)	false
 #endif
 
 #ifndef pud_user_accessible_page
-#define pud_user_accessible_page(pud, addr)	false
+#define pud_user_accessible_page(mm, addr, pud)	false
 #endif
 
 #endif /* __ASSEMBLER__ */
arch/riscv/include/asm/pgtable.h +3 -3
index 08d1ca047104..affe46cf3bc5 100644
@@ -984,17 +984,17 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
 }
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return pte_present(pte) && pte_user(pte);
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
 {
 	return pmd_leaf(pmd) && pmd_user(pmd);
 }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
 {
 	return pud_leaf(pud) && pud_user(pud);
 }
arch/x86/include/asm/pgtable.h +3 -3
index 1662c5a8f445..f9353d5c7464 100644
@@ -1680,17 +1680,17 @@ static inline bool arch_has_hw_nonleaf_pmd_young(void)
 #endif
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
 {
 	return (pte_val(pte) & _PAGE_PRESENT) && (pte_val(pte) & _PAGE_USER);
 }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
 {
 	return pmd_leaf(pmd) && (pmd_val(pmd) & _PAGE_PRESENT) && (pmd_val(pmd) & _PAGE_USER);
 }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
 {
 	return pud_leaf(pud) && (pud_val(pud) & _PAGE_PRESENT) && (pud_val(pud) & _PAGE_USER);
 }
mm/page_table_check.c +6 -9
index 2708c2b3ac1f..53a8997ec043 100644
@@ -151,9 +151,8 @@ void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pte_user_accessible_page(pte, addr)) {
+	if (pte_user_accessible_page(mm, addr, pte))
 		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
-	}
 }
 EXPORT_SYMBOL(__page_table_check_pte_clear);
 
@@ -163,9 +162,8 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pmd_user_accessible_page(pmd, addr)) {
+	if (pmd_user_accessible_page(mm, addr, pmd))
 		page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
-	}
 }
 EXPORT_SYMBOL(__page_table_check_pmd_clear);
 
@@ -175,9 +173,8 @@ void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
 	if (&init_mm == mm)
 		return;
 
-	if (pud_user_accessible_page(pud, addr)) {
+	if (pud_user_accessible_page(mm, addr, pud))
 		page_table_check_clear(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT);
-	}
 }
 EXPORT_SYMBOL(__page_table_check_pud_clear);
 
@@ -211,7 +208,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
-	if (pte_user_accessible_page(pte, addr))
+	if (pte_user_accessible_page(mm, addr, pte))
 		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
 }
 EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -241,7 +238,7 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
-	if (pmd_user_accessible_page(pmd, addr))
+	if (pmd_user_accessible_page(mm, addr, pmd))
 		page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
 }
 EXPORT_SYMBOL(__page_table_check_pmds_set);
@@ -257,7 +254,7 @@ void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
-	if (pud_user_accessible_page(pud, addr))
+	if (pud_user_accessible_page(mm, addr, pud))
 		page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
 }
 EXPORT_SYMBOL(__page_table_check_puds_set);
Signature · 1 line
2.51.0
#2 lore raw

Re: [PATCH v2 1/4] mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

Quoted 15 lines · Alexander Gordeev

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

[[email protected]: rephrased commit message, removed braces]

Quoted 6 lines
---
 arch/arm64/include/asm/pgtable.h             |  6 +++---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 ++--

straightforward change for adding mm struct param in the page table check calls. Also verified building different powerpc configs using ci.

The changes looks good to me. Please feel free to add:

Reviewed-by Ritesh Harjani (IBM) <[email protected]> #powerpc

maintainer Acked-by on v2 1/4
#3 lore raw

Re: [PATCH v2 1/4] mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

In reply to Alexander Gordeev
Quoted 8 lines · Alexander Gordeev

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

Changes looks fine to me

Quoted 237 lines

[[email protected]: rephrased commit message, removed braces]

---
  arch/arm64/include/asm/pgtable.h             |  6 +++---
  arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
  arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
  arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
  arch/powerpc/include/asm/pgtable.h           |  4 ++--
  arch/riscv/include/asm/pgtable.h             |  6 +++---
  arch/x86/include/asm/pgtable.h               |  6 +++---
  mm/page_table_check.c                        | 15 ++++++---------
  8 files changed, 24 insertions(+), 27 deletions(-)
arch/arm64/include/asm/pgtable.h +3 -3
index b3e58735c49b..ccf0e0638767 100644
@@ -1263,17 +1263,17 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
  #endif
 
  #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
  }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
  {
  	return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
  }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
  {
  	return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
  }
arch/powerpc/include/asm/book3s/32/pgtable.h +1 -1
index 001e28f9eabc..75195bb44d06 100644
@@ -438,7 +438,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
  	return true;
  }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return pte_present(pte) && !is_kernel_addr(addr);
  }
arch/powerpc/include/asm/book3s/64/pgtable.h +5 -5
index 1a91762b455d..a56df313b585 100644
@@ -549,7 +549,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
  	return arch_pte_access_permitted(pte_val(pte), write, 0);
  }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return pte_present(pte) && pte_user(pte);
  }
@@ -925,9 +925,9 @@ static inline bool pud_access_permitted(pud_t pud, bool write)
  }
 
  #define pud_user_accessible_page pud_user_accessible_page
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
  {
-	return pud_leaf(pud) && pte_user_accessible_page(pud_pte(pud), addr);
+	return pud_leaf(pud) && pte_user_accessible_page(mm, addr, pud_pte(pud));
  }
 
  #define __p4d_raw(x)	((p4d_t) { __pgd_raw(x) })
@@ -1096,9 +1096,9 @@ static inline bool pmd_access_permitted(pmd_t pmd, bool write)
  }
 
  #define pmd_user_accessible_page pmd_user_accessible_page
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
  {
-	return pmd_leaf(pmd) && pte_user_accessible_page(pmd_pte(pmd), addr);
+	return pmd_leaf(pmd) && pte_user_accessible_page(mm, addr, pmd_pte(pmd));
  }
 
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
arch/powerpc/include/asm/nohash/pgtable.h +1 -1
index e6da5eaccff6..0665d0abe89f 100644
@@ -249,7 +249,7 @@ static inline bool pte_access_permitted(pte_t pte, bool write)
  	return true;
  }
 
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return pte_present(pte) && !is_kernel_addr(addr);
  }
arch/powerpc/include/asm/pgtable.h +2 -2
index dcd3a88caaf6..29ed509cd235 100644
@@ -205,11 +205,11 @@ static inline bool arch_supports_memmap_on_memory(unsigned long vmemmap_size)
  #endif /* CONFIG_PPC64 */
 
  #ifndef pmd_user_accessible_page
-#define pmd_user_accessible_page(pmd, addr)	false
+#define pmd_user_accessible_page(mm, addr, pmd)	false
  #endif
 
  #ifndef pud_user_accessible_page
-#define pud_user_accessible_page(pud, addr)	false
+#define pud_user_accessible_page(mm, addr, pud)	false
  #endif
 
  #endif /* __ASSEMBLER__ */
arch/riscv/include/asm/pgtable.h +3 -3
index 08d1ca047104..affe46cf3bc5 100644
@@ -984,17 +984,17 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
  }
 
  #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return pte_present(pte) && pte_user(pte);
  }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
  {
  	return pmd_leaf(pmd) && pmd_user(pmd);
  }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
  {
  	return pud_leaf(pud) && pud_user(pud);
  }
arch/x86/include/asm/pgtable.h +3 -3
index 1662c5a8f445..f9353d5c7464 100644
@@ -1680,17 +1680,17 @@ static inline bool arch_has_hw_nonleaf_pmd_young(void)
  #endif
 
  #ifdef CONFIG_PAGE_TABLE_CHECK
-static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
  {
  	return (pte_val(pte) & _PAGE_PRESENT) && (pte_val(pte) & _PAGE_USER);
  }
 
-static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+static inline bool pmd_user_accessible_page(struct mm_struct *mm, unsigned long addr, pmd_t pmd)
  {
  	return pmd_leaf(pmd) && (pmd_val(pmd) & _PAGE_PRESENT) && (pmd_val(pmd) & _PAGE_USER);
  }
 
-static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+static inline bool pud_user_accessible_page(struct mm_struct *mm, unsigned long addr, pud_t pud)
  {
  	return pud_leaf(pud) && (pud_val(pud) & _PAGE_PRESENT) && (pud_val(pud) & _PAGE_USER);
  }
mm/page_table_check.c +6 -9
index 2708c2b3ac1f..53a8997ec043 100644
@@ -151,9 +151,8 @@ void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
  	if (&init_mm == mm)
  		return;
 
-	if (pte_user_accessible_page(pte, addr)) {
+	if (pte_user_accessible_page(mm, addr, pte))
  		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
-	}
  }
  EXPORT_SYMBOL(__page_table_check_pte_clear);
 
@@ -163,9 +162,8 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
  	if (&init_mm == mm)
  		return;
 
-	if (pmd_user_accessible_page(pmd, addr)) {
+	if (pmd_user_accessible_page(mm, addr, pmd))
  		page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
-	}
  }
  EXPORT_SYMBOL(__page_table_check_pmd_clear);
 
@@ -175,9 +173,8 @@ void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
  	if (&init_mm == mm)
  		return;
 
-	if (pud_user_accessible_page(pud, addr)) {
+	if (pud_user_accessible_page(mm, addr, pud))
  		page_table_check_clear(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT);
-	}
  }
  EXPORT_SYMBOL(__page_table_check_pud_clear);
 
@@ -211,7 +208,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
 
  	for (i = 0; i < nr; i++)
  		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
-	if (pte_user_accessible_page(pte, addr))
+	if (pte_user_accessible_page(mm, addr, pte))
  		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
  }
  EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -241,7 +238,7 @@ void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
 
  	for (i = 0; i < nr; i++)
  		__page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
-	if (pmd_user_accessible_page(pmd, addr))
+	if (pmd_user_accessible_page(mm, addr, pmd))
  		page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
  }
  EXPORT_SYMBOL(__page_table_check_pmds_set);
@@ -257,7 +254,7 @@ void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
 
  	for (i = 0; i < nr; i++)
  		__page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
-	if (pud_user_accessible_page(pud, addr))
+	if (pud_user_accessible_page(mm, addr, pud))
  		page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
  }
  EXPORT_SYMBOL(__page_table_check_puds_set);
maintainer
#4 lore raw

Re: [PATCH v2 1/4] mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

In reply to Alexander Gordeev
Quoted 15 lines · Alexander Gordeev

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

[[email protected]: rephrased commit message, removed braces]

Quoted 10 lines
---
 arch/arm64/include/asm/pgtable.h             |  6 +++---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 ++--
 arch/riscv/include/asm/pgtable.h             |  6 +++---
 arch/x86/include/asm/pgtable.h               |  6 +++---
 mm/page_table_check.c                        | 15 ++++++---------
 8 files changed, 24 insertions(+), 27 deletions(-)

Andrew, may I get your Reviewed-by or Ack-by for v2 so I can take it via the s390 tree as well?

Thank you.

maintainer Reviewed-by
#5 lore raw

Re: [PATCH v2 1/4] mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

Quoted 27 lines · On Thu, 12 Mar 2026 16:02:40 +0100 Vasily Gorbik <[email protected]> wrote:
Quoted 15 lines · Alexander Gordeev

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

[[email protected]: rephrased commit message, removed braces]

Quoted 10 lines
---
 arch/arm64/include/asm/pgtable.h             |  6 +++---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 ++--
 arch/riscv/include/asm/pgtable.h             |  6 +++---
 arch/x86/include/asm/pgtable.h               |  6 +++---
 mm/page_table_check.c                        | 15 ++++++---------
 8 files changed, 24 insertions(+), 27 deletions(-)
Quoted 2 lines

Andrew, may I get your Reviewed-by or Ack-by for v2 so I can take it via the s390 tree as well?

It doesn't look like [1/4] changed significanty since v1?

maintainer
#6 lore raw

Re: [PATCH v2 1/4] mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()

Quoted 12 lines · Andrew Morton
Quoted 10 lines · On Thu, 12 Mar 2026 16:02:40 +0100 Vasily Gorbik <[email protected]> wrote:
Quoted 9 lines · Alexander Gordeev

From: Tobias Huschle <[email protected]>

Unlike other architectures, s390 does not have means to distinguish kernel vs user page table entries - neither an entry itself, nor the address could be used for that. It is only the mm_struct that indicates whether an entry in question is mapped to a user space. So pass mm_struct to pxx_user_accessible_page() callbacks.

...

Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
---
 arch/arm64/include/asm/pgtable.h             |  6 +++---
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +++++-----
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 ++--
 arch/riscv/include/asm/pgtable.h             |  6 +++---
 arch/x86/include/asm/pgtable.h               |  6 +++---
 mm/page_table_check.c                        | 15 ++++++---------
 8 files changed, 24 insertions(+), 27 deletions(-)
Quoted 6 lines
Quoted 2 lines

Andrew, may I get your Reviewed-by or Ack-by for v2 so I can take it via the s390 tree as well?

It doesn't look like [1/4] changed significanty since v1?

PowerPC page table check support landed at the same time v1 was sent, so v1 was missing PowerPC header changes, which was reported by the kernel test robot:
https://lore.kernel.org/all/[email protected]/
Hence, v2 to address that.

author maintainer
#7 lore raw

PATCH v2 2/4 s390/pgtable: Use set_pmd_bit() to invalidate PMD entry

In reply to Alexander Gordeev

Commit 3a5a8d343e1c ("mm: fix race between __split_huge_pmd_locked() and GUP-fast") failed to follow the convention and used direct PMD entry modification instead of set_pmd_bit().

---
 arch/s390/include/asm/pgtable.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/s390/include/asm/pgtable.h +3 -3
index 1c3c3be93be9..04ec9fee6498 100644
@@ -1744,10 +1744,10 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma,
 static inline pmd_t pmdp_invalidate(struct vm_area_struct *vma,
 				   unsigned long addr, pmd_t *pmdp)
 {
-	pmd_t pmd;
+	pmd_t pmd = *pmdp;
 
-	VM_WARN_ON_ONCE(!pmd_present(*pmdp));
-	pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID);
+	VM_WARN_ON_ONCE(!pmd_present(pmd));
+	pmd = set_pmd_bit(pmd, __pgprot(_SEGMENT_ENTRY_INVALID));
 	return pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd);
 }
 
Signature · 1 line
2.51.0
author maintainer
#8 lore raw

PATCH v2 3/4 s390/pgtable: Add s390 support for page table check

In reply to Alexander Gordeev

From: Tobias Huschle <[email protected]>

Add page table check hooks into routines that modify user page tables.

Unlike other architectures s390 does not have means to distinguish between kernel and user page table entries. Rely on the fact the page table check infrastructure itself operates on non-init_mm memory spaces only.

Use the provided mm_struct to verify that the memory space is not init_mm (aka not the kernel memory space) indeed. That check is supposed to be succeeded already (on some code paths even twice).

If the passed memory space by contrast is init_mm that would be an unexpected semantical change in generic code, so do VM_BUG_ON() in such case.

Unset _SEGMENT_ENTRY_READ bit to indicate that pmdp_invalidate() was applied against a huge PMD and is going to be updated by set_pmd_at() shortly. The hook pmd_user_accessible_page() should skip such entries until that, otherwise the page table accounting falls apart and BUG_ON() gets hit as result.

The invalidated huge PMD entry should not be confused with a PROT_NONE entry as reported by pmd_protnone(), though the entry characteristics exactly match: _SEGMENT_ENTRY_LARGE is set while _SEGMENT_ENTRY_READ is unset. Since pmd_protnone() implementation depends on NUMA_BALANCING configuration option, it should not be used in pmd_user_accessible_page() check, which is expected to be CONFIG_NUMA_BALANCING-agnostic.

Nevertheless, an invalidated huge PMD is technically still pmd_protnone() entry and it should not break other code paths once _SEGMENT_ENTRY_READ is unset. As of now, all pmd_protnone() checks are done under page table locks or exercise GUP-fast and HMM code paths, which are expected to be safe against concurrent page table updates.

Alternative approach would be using the last remaining unused PMD entry bit 0x800 to indicate that pmdp_invalidate() was called on a PMD. That would allow avoiding collisions with pmd_protnone() handling code paths, but saving the bit is more preferable way to go.

---
 arch/s390/Kconfig               |  1 +
 arch/s390/include/asm/pgtable.h | 54 ++++++++++++++++++++++++++++++---
 2 files changed, 51 insertions(+), 4 deletions(-)
arch/s390/Kconfig +1 -0
index edc927d9e85a..7bda45d30455 100644
@@ -154,6 +154,7 @@ config S390
 	select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && CC_IS_CLANG
 	select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
 	select ARCH_SUPPORTS_NUMA_BALANCING
+	select ARCH_SUPPORTS_PAGE_TABLE_CHECK
 	select ARCH_SUPPORTS_PER_VMA_LOCK
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF
arch/s390/include/asm/pgtable.h +50 -4

120 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#9 lore raw

PATCH v2 4/4 s390: Enable page table check for debug_defconfig

In reply to Alexander Gordeev
---
 arch/s390/configs/debug_defconfig | 2 ++
 1 file changed, 2 insertions(+)
arch/s390/configs/debug_defconfig +2 -0
index 98fd0a2f51c6..12cdaaefb6db 100644
@@ -929,3 +929,5 @@ CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_TEST_BITOPS=m
 CONFIG_TEST_BPF=m
+CONFIG_PAGE_TABLE_CHECK=y
+CONFIG_PAGE_TABLE_CHECK_ENFORCED=y
Signature · 1 line
2.51.0
maintainer Applied
#10 lore raw
In reply to Alexander Gordeev
Quoted 18 lines · Alexander Gordeev

Hi All,

In v7.0-rc1 page table check support for PPC was added, which conflicted with this series v1. Thus the only change in v2 is PPC headers update, which still is NOP for non-s390.

I only did compile test for PPC.

Thanks!

Alexander Gordeev (2):
s390/pgtable: Use set_pmd_bit() to invalidate PMD entry
s390: Enable page table check for debug_defconfig

Tobias Huschle (2):
mm/page_table_check: Pass mm_struct to pxx_user_accessible_page() s390/pgtable: Add s390 support for page table check

Quoted 12 lines
 arch/arm64/include/asm/pgtable.h             |  6 +-
 arch/powerpc/include/asm/book3s/32/pgtable.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h | 10 ++--
 arch/powerpc/include/asm/nohash/pgtable.h    |  2 +-
 arch/powerpc/include/asm/pgtable.h           |  4 +-
 arch/riscv/include/asm/pgtable.h             |  6 +-
 arch/s390/Kconfig                            |  1 +
 arch/s390/configs/debug_defconfig            |  2 +
 arch/s390/include/asm/pgtable.h              | 60 +++++++++++++++++---
 arch/x86/include/asm/pgtable.h               |  6 +-
 mm/page_table_check.c                        | 15 ++---
 11 files changed, 80 insertions(+), 34 deletions(-)

Applied to the s390 tree, thank you!