[RFC PATCH 4/4] s390/mm: implement __ptent-aware pte_t type

Alexander Gordeev <[email protected]> Fri, 17 Jul 2026 15:32:22 +0200
Newsgroups org.kernel.vger.linux-sparse,org.kernel.vger.linux-kernel,org.kernel.vger.linux-s390,org.kvack.linux-mm
Message-ID <2580c0c643125fb89247f255ff42803bea44e4c3.1784292223.git.agordeev@linux.ibm.com>
Signed-off-by: Alexander Gordeev <[email protected]>
---
 arch/s390/include/asm/page.h    | 16 ++++++++++--
 arch/s390/include/asm/pgtable.h | 44 +++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 56da819a79e6..ce68994a0292 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -76,8 +76,10 @@ static inline void copy_page(void *to, void *from)
=20
 #ifdef STRICT_MM_TYPECHECKS
=20
+typedef struct { unsigned long pte; } pteraw_t;
+typedef pteraw_t __ptent pte_t;
+
 typedef struct { unsigned long pgprot; } pgprot_t;
-typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pud; } pud_t;
 typedef struct { unsigned long p4d; } p4d_t;
@@ -89,6 +91,11 @@ static __always_inline unsigned long name ## _val(name=
 ## _t name)	\
 	return name.name;						\
 }
=20
+static inline unsigned long pte_val(pte_t pte)
+{
+	return ((__force pteraw_t *)&pte)->pte;
+}
+
 #else /* STRICT_MM_TYPECHECKS */
=20
 typedef unsigned long pgprot_t;
@@ -98,6 +105,11 @@ typedef unsigned long pud_t;
 typedef unsigned long p4d_t;
 typedef unsigned long pgd_t;
=20
+static inline unsigned long pte_val(pte_t pte)
+{
+	return pte;
+}
+
 #define DEFINE_PGVAL_FUNC(name)						\
 static __always_inline unsigned long name ## _val(name ## _t name)	\
 {									\
@@ -107,7 +119,6 @@ static __always_inline unsigned long name ## _val(nam=
e ## _t name)	\
 #endif /* STRICT_MM_TYPECHECKS */
=20
 DEFINE_PGVAL_FUNC(pgprot)
-DEFINE_PGVAL_FUNC(pte)
 DEFINE_PGVAL_FUNC(pmd)
 DEFINE_PGVAL_FUNC(pud)
 DEFINE_PGVAL_FUNC(p4d)
@@ -116,6 +127,7 @@ DEFINE_PGVAL_FUNC(pgd)
 typedef pte_t *pgtable_t;
=20
 #define __pgprot(x)	((pgprot_t) { (x) } )
+#define __pteraw(x)	((pteraw_t) { (x) } )
 #define __pte(x)        ((pte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
 #define __pud(x)	((pud_t) { (x) } )
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgta=
ble.h
index 859ce7c7d454..6398f58c09ce 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -978,6 +978,49 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 	WRITE_ONCE(*pmdp, pmd);
 }
=20
+#ifdef STRICT_MM_TYPECHECKS
+static inline void set_pte(pte_t *ptep, pte_t pte)
+{
+	pteraw_t *pteraw_ptep =3D (__force pteraw_t *)ptep;
+	pteraw_t pteraw =3D __pteraw(pte_val(pte));
+
+	if (pte_present(pte))
+		pte =3D clear_pte_bit(pte, __pgprot(_PAGE_UNUSED));
+	WRITE_ONCE(*pteraw_ptep, pteraw);
+}
+
+#define ptep_get ptep_get
+static inline pte_t ptep_get(pte_t *ptep)
+{
+	pteraw_t *pteraw_ptep =3D (__force pteraw_t *)ptep;
+	pteraw_t pteraw =3D READ_ONCE(*pteraw_ptep);
+
+	return __pte(pteraw.pte);
+}
+
+#define ptep_get_nopgtable ptep_get_nopgtable
+static inline pte_t ptep_get_nopgtable(pte_t *ptep)
+{
+	/*
+	 * Ensure this is a pointer to a copy not a pointer into a page table.
+	 * If this is a stack value, it won't be a valid virtual address, but
+	 * that's fine because it also cannot be pointing into the page table.
+	 */
+	VM_WARN_ON(virt_addr_valid(ptep) && PageTable(virt_to_page(ptep)));
+
+	return (__force pte_t)(*(pteraw_t *)ptep);
+}
+
+#define set_pte_nopgtable set_pte_nopgtable
+static inline void set_pte_nopgtable(pte_t *ptep, pte_t pte)
+{
+	/*
+	 * See comment in ptep_get_nopgtable().
+	 */
+	VM_WARN_ON(virt_addr_valid(ptep) && PageTable(virt_to_page(ptep)));
+	*(pteraw_t *)ptep =3D (__force pteraw_t)pte;
+}
+#else
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
 	if (pte_present(pte))
@@ -990,6 +1033,7 @@ static inline pte_t ptep_get(pte_t *ptep)
 {
 	return READ_ONCE(*ptep);
 }
+#endif
=20
 #define pmdp_get pmdp_get
 static inline pmd_t pmdp_get(pmd_t *pmdp)
--=20
2.53.0