* [RFC PATCH 0/4] mm: introduce __ptent sparse attribute
@ 2026-07-17 13:32 Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap() Alexander Gordeev
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Alexander Gordeev @ 2026-07-17 13:32 UTC (permalink / raw)
To: Kevin Brodsky, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
Hi All!
This RFC is a result the implementation of lazy MMU mode on s390 [1].
Heiko Carstens requested some mechanism that would rule out direct
dereferencing of PTE pointers, which otherwise would bypass the per-
cpu cache on s390 and lead to catastrophic results.
This is an attempt to introduce __ptent sparse attribute similar to
__private, but to be applied only to pte_t type by architectures.
When used with C=1 the modified sparse "dereference of PTE pointer"
warning is emitted.
With using that new mechanism I was able to identify direct PTE
pointer dereferences, which should not have existed after commit
c33c794828f2 ("mm: ptep_get() conversion") (and its follow-ups).
In addition to ptep_get() and set_pte() accessors I suggest to
introduce ptep_get_nopgtable() and set_pte_nopgtable() variants
to use when a PTE pointer does not point to the page table, but
rather to a copy of the PTE. These would allow dropping unnecessary
checks on s390, but is already the case for folio_pte_batch_flags().
Patches 1,2 are independent from the sparse rework and are good to go AFAICT.
Patch 3 is the required change to be coupled with the sparse rework below.
Patch 4 is an example of how __ptent was implemented on s390.
I hesitate to post the sparse patch itself before the rework is is agreed,
but I am CC-ing the sparse mailing list.
1. https://lore.kernel.org/linux-s390/cover.1784121418.git.agordeev@linux.ibm.com/
2. https://lore.kernel.org/linux-s390/20260423122824.10371E07-hca@linux.ibm.com/
Thanks!
diff --git a/expand.c b/expand.c
index f14e7181..a06b005c 100644
--- a/expand.c
+++ b/expand.c
@@ -718,6 +718,8 @@ static int expand_dereference(struct expression *expr)
*/
if (expr->ctype->ctype.modifiers & MOD_NODEREF)
warning(unop->pos, "dereference of noderef expression");
+ if ((expr->ctype->ctype.modifiers & MOD_PTENT) && unop->ctype != &lazy_ptr_ctype)
+ warning(unop->pos, "dereference of PTE pointer");
/*
* Is it "symbol" or "symbol + offset"?
diff --git a/parse.c b/parse.c
index 9389079e..213faeaf 100644
--- a/parse.c
+++ b/parse.c
@@ -553,6 +553,7 @@ static struct init_keyword {
D("cleanup", &cleanup_op),
D("nocast", &attr_mod_op, .mods = MOD_NOCAST),
D("noderef", &attr_mod_op, .mods = MOD_NODEREF),
+ D("ptent", &attr_mod_op, .mods = MOD_PTENT),
D("safe", &attr_mod_op, .mods = MOD_SAFE),
D("unused", &attr_mod_op, .mods = MOD_UNUSED),
D("externally_visible", &attr_mod_op, .mods = MOD_EXT_VISIBLE),
diff --git a/show-parse.c b/show-parse.c
index ceb6b3cb..0784d51d 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -135,6 +135,7 @@ static const char *show_modifiers(unsigned long mod, int term)
{MOD_GNU_INLINE, "[gnu_inline]"},
{MOD_NOCAST, "[nocast]"},
{MOD_NODEREF, "[noderef]"},
+ {MOD_PTENT, "[ptent]"},
{MOD_NORETURN, "[noreturn]"},
{MOD_PURE, "[pure]"},
{MOD_SAFE, "[safe]"},
diff --git a/symbol.h b/symbol.h
index 3552d439..5fb1a811 100644
--- a/symbol.h
+++ b/symbol.h
@@ -247,7 +247,7 @@ struct symbol {
#define MOD_GNU_INLINE 0x00010000
#define MOD_USERTYPE 0x00020000
- // MOD UNUSED 0x00040000
+#define MOD_PTENT 0x00040000
// MOD UNUSED 0x00080000
// MOD UNUSED 0x00100000
// MOD UNUSED 0x00200000
@@ -270,9 +270,9 @@ struct symbol {
#define MOD_SPECIFIER MOD_SIGNEDNESS
#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED | MOD_EXT_VISIBLE | MOD_UNUSED | MOD_GNU_INLINE)
#define MOD_QUALIFIER (MOD_CONST | MOD_VOLATILE | MOD_RESTRICT)
-#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_ATOMIC | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
+#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_ATOMIC | MOD_NODEREF | MOD_PTENT | MOD_NORETURN | MOD_NOCAST)
/* modifiers preserved by typeof() operator */
-#define MOD_TYPEOF (MOD_QUALIFIER | MOD_ATOMIC | MOD_NOCAST | MOD_SPECIFIER)
+#define MOD_TYPEOF (MOD_QUALIFIER | MOD_ATOMIC | MOD_NOCAST | MOD_SPECIFIER | MOD_PTENT)
/* modifiers for function attributes */
#define MOD_FUN_ATTR (MOD_PURE|MOD_NORETURN)
/* like cvr-qualifiers but 'reversed' (OK: source <= target) */
Alexander Gordeev (4):
mm: use proper PTE accessors in madvise() and mremap()
mm: introduce ptep_get_nopgtable() and set_pte_nopgtable() accessors
mm: introduce __ptent sparse attribute
s390/mm: implement __ptent-aware pte_t type
arch/s390/include/asm/page.h | 16 ++++++++++--
arch/s390/include/asm/pgtable.h | 44 +++++++++++++++++++++++++++++++++
include/linux/compiler_types.h | 2 ++
include/linux/pgtable.h | 25 +++++++++++++++++++
mm/internal.h | 16 +++++-------
mm/ksm.c | 2 +-
mm/madvise.c | 2 +-
mm/mremap.c | 2 +-
8 files changed, 94 insertions(+), 15 deletions(-)
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap()
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
@ 2026-07-17 13:32 ` Alexander Gordeev
2026-07-17 17:14 ` Kevin Brodsky
2026-07-17 13:32 ` [RFC PATCH 2/4] mm: introduce ptep_get_nopgtable() and set_pte_nopgtable() accessors Alexander Gordeev
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Alexander Gordeev @ 2026-07-17 13:32 UTC (permalink / raw)
To: Kevin Brodsky, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
Follow the pattern established by commit c33c794828f2 ("mm:
ptep_get() conversion") and use proper accessors instead of
direct pointer dereferences.
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
---
mm/madvise.c | 2 +-
mm/mremap.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/madvise.c b/mm/madvise.c
index 77552b03d318..7d369b1ff8e5 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1106,7 +1106,7 @@ static int guard_install_set_pte(unsigned long addr, unsigned long next,
unsigned long *nr_pages = (unsigned long *)walk->private;
/* Simply install a PTE marker, this causes segfault on access. */
- *ptep = make_pte_marker(PTE_MARKER_GUARD);
+ set_pte(ptep, make_pte_marker(PTE_MARKER_GUARD));
(*nr_pages)++;
return 0;
diff --git a/mm/mremap.c b/mm/mremap.c
index e9c8b1d05832..fc3b90274a57 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -264,7 +264,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE,
new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) {
- VM_WARN_ON_ONCE(!pte_none(*new_ptep));
+ VM_WARN_ON_ONCE(!pte_none(ptep_get(new_ptep)));
nr_ptes = 1;
max_nr_ptes = (old_end - old_addr) >> PAGE_SHIFT;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 2/4] mm: introduce ptep_get_nopgtable() and set_pte_nopgtable() accessors
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap() Alexander Gordeev
@ 2026-07-17 13:32 ` Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 3/4] mm: introduce __ptent sparse attribute Alexander Gordeev
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Alexander Gordeev @ 2026-07-17 13:32 UTC (permalink / raw)
To: Kevin Brodsky, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
Add helpers to safely access PTE values stored outside page
tables, such as in stack variables or temporary copies. These
adopt the check from folio_pte_batch_flags() to ensure the
pointer does not point into an actual page table.
Follow the pattern established by commit c33c794828f2 ("mm:
ptep_get() conversion") and use the new accessors instead of
direct pointer dereferences.
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
---
include/linux/pgtable.h | 25 +++++++++++++++++++++++++
mm/internal.h | 16 ++++++----------
mm/ksm.c | 2 +-
3 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2981e386da7b..e38f045d0e73 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -489,6 +489,31 @@ static inline int pudp_set_access_flags(struct vm_area_struct *vma,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
+#ifndef 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 *ptep;
+}
+#endif
+
+#ifndef 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)));
+ *ptep = pte;
+}
+#endif
+
#ifndef ptep_get
static inline pte_t ptep_get(pte_t *ptep)
{
diff --git a/mm/internal.h b/mm/internal.h
index 181e79f1d6a2..0d04a107962a 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -339,18 +339,12 @@ static inline unsigned int folio_pte_batch_flags(struct folio *folio,
unsigned int max_nr, fpb_t flags)
{
bool any_writable = false, any_young = false, any_dirty = false;
- pte_t expected_pte, pte = *ptentp;
+ pte_t expected_pte, pte = ptep_get_nopgtable(ptentp);
unsigned int nr, cur_nr;
VM_WARN_ON_FOLIO(!pte_present(pte), folio);
VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio);
VM_WARN_ON_FOLIO(page_folio(pfn_to_page(pte_pfn(pte))) != folio, folio);
- /*
- * 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(ptentp) && PageTable(virt_to_page(ptentp)));
/* Limit max_nr to the actual remaining PFNs in the folio we could batch. */
max_nr = min_t(unsigned long, max_nr,
@@ -379,12 +373,14 @@ static inline unsigned int folio_pte_batch_flags(struct folio *folio,
nr += cur_nr;
}
+ pte = ptep_get_nopgtable(ptentp);
if (any_writable)
- *ptentp = pte_mkwrite(*ptentp, vma);
+ pte = pte_mkwrite(pte, vma);
if (any_young)
- *ptentp = pte_mkyoung(*ptentp);
+ pte = pte_mkyoung(pte);
if (any_dirty)
- *ptentp = pte_mkdirty(*ptentp);
+ pte = pte_mkdirty(pte);
+ set_pte_nopgtable(ptentp, pte);
return min(nr, max_nr);
}
diff --git a/mm/ksm.c b/mm/ksm.c
index 7d5b76478f0b..5b22c602a105 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1352,7 +1352,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
set_pte_at(mm, pvmw.address, pvmw.pte, entry);
}
- *orig_pte = entry;
+ set_pte_nopgtable(orig_pte, entry);
err = 0;
out_unlock:
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 3/4] mm: introduce __ptent sparse attribute
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap() Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 2/4] mm: introduce ptep_get_nopgtable() and set_pte_nopgtable() accessors Alexander Gordeev
@ 2026-07-17 13:32 ` Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 4/4] s390/mm: implement __ptent-aware pte_t type Alexander Gordeev
2026-07-17 14:53 ` [RFC PATCH 0/4] mm: introduce __ptent sparse attribute David Hildenbrand (Arm)
4 siblings, 0 replies; 7+ messages in thread
From: Alexander Gordeev @ 2026-07-17 13:32 UTC (permalink / raw)
To: Kevin Brodsky, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
Introduce a new __ptent sparse attribute to enable type checking for
page table entries. This attribute would mark architecture-specific
pte_t type, whose pointers should only be accessed through proper
accessors, such like ptep_get(), set_pte() etc.
The corresponding sparse tool rework for this attribute is required
to cause the "dereference of PTE pointer" warning.
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
---
include/linux/compiler_types.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index c5921f139007..472af4fb2546 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -58,6 +58,7 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
# define __nocast __attribute__((nocast))
# define __safe __attribute__((safe))
# define __private __attribute__((noderef))
+# define __ptent __attribute__((ptent))
# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member))
#else /* __CHECKER__ */
/* address spaces */
@@ -78,6 +79,7 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
# define __nocast
# define __safe
# define __private
+# define __ptent
# define ACCESS_PRIVATE(p, member) ((p)->member)
# define __builtin_warning(x, y...) (1)
#endif /* __CHECKER__ */
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 4/4] s390/mm: implement __ptent-aware pte_t type
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
` (2 preceding siblings ...)
2026-07-17 13:32 ` [RFC PATCH 3/4] mm: introduce __ptent sparse attribute Alexander Gordeev
@ 2026-07-17 13:32 ` Alexander Gordeev
2026-07-17 14:53 ` [RFC PATCH 0/4] mm: introduce __ptent sparse attribute David Hildenbrand (Arm)
4 siblings, 0 replies; 7+ messages in thread
From: Alexander Gordeev @ 2026-07-17 13:32 UTC (permalink / raw)
To: Kevin Brodsky, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
---
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)
#ifdef STRICT_MM_TYPECHECKS
+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; \
}
+static inline unsigned long pte_val(pte_t pte)
+{
+ return ((__force pteraw_t *)&pte)->pte;
+}
+
#else /* STRICT_MM_TYPECHECKS */
typedef unsigned long pgprot_t;
@@ -98,6 +105,11 @@ typedef unsigned long pud_t;
typedef unsigned long p4d_t;
typedef unsigned long pgd_t;
+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(name ## _t name) \
#endif /* STRICT_MM_TYPECHECKS */
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;
#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/pgtable.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);
}
+#ifdef STRICT_MM_TYPECHECKS
+static inline void set_pte(pte_t *ptep, pte_t pte)
+{
+ pteraw_t *pteraw_ptep = (__force pteraw_t *)ptep;
+ pteraw_t pteraw = __pteraw(pte_val(pte));
+
+ if (pte_present(pte))
+ pte = 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 = (__force pteraw_t *)ptep;
+ pteraw_t pteraw = 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 = (__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
#define pmdp_get pmdp_get
static inline pmd_t pmdp_get(pmd_t *pmdp)
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 0/4] mm: introduce __ptent sparse attribute
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
` (3 preceding siblings ...)
2026-07-17 13:32 ` [RFC PATCH 4/4] s390/mm: implement __ptent-aware pte_t type Alexander Gordeev
@ 2026-07-17 14:53 ` David Hildenbrand (Arm)
4 siblings, 0 replies; 7+ messages in thread
From: David Hildenbrand (Arm) @ 2026-07-17 14:53 UTC (permalink / raw)
To: Alexander Gordeev, Kevin Brodsky, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse,
Muhammad Usama Anjum
On 7/17/26 14:32, Alexander Gordeev wrote:
> Hi All!
>
> This RFC is a result the implementation of lazy MMU mode on s390 [1].
>
> Heiko Carstens requested some mechanism that would rule out direct
> dereferencing of PTE pointers, which otherwise would bypass the per-
> cpu cache on s390 and lead to catastrophic results.
>
> This is an attempt to introduce __ptent sparse attribute similar to
> __private, but to be applied only to pte_t type by architectures.
> When used with C=1 the modified sparse "dereference of PTE pointer"
> warning is emitted.
>
> With using that new mechanism I was able to identify direct PTE
> pointer dereferences, which should not have existed after commit
> c33c794828f2 ("mm: ptep_get() conversion") (and its follow-ups).
>
> In addition to ptep_get() and set_pte() accessors I suggest to
> introduce ptep_get_nopgtable() and set_pte_nopgtable() variants
> to use when a PTE pointer does not point to the page table, but
> rather to a copy of the PTE. These would allow dropping unnecessary
> checks on s390, but is already the case for folio_pte_batch_flags().
>
> Patches 1,2 are independent from the sparse rework and are good to go AFAICT.
> Patch 3 is the required change to be coupled with the sparse rework below.
> Patch 4 is an example of how __ptent was implemented on s390.
>
> I hesitate to post the sparse patch itself before the rework is is agreed,
> but I am CC-ing the sparse mailing list.
Usama is working on something bigger, whereby we introduce the concept of pte_t
and hw_pte_t in common code, and allow to decouple them on architectures that
really need (IOW that implement it in their arch code).
On architecture that decouple both types, the compiler will do the type checking
for us.
The prototype patches I saw looked pretty encouraging (at least for pte_t, pmd_t
is more involved).
There is some information here:
https://lore.kernel.org/r/6110202c-057b-4701-8c04-1a76ee7bb9ab@arm.com
And I'm sure Usama can share some more details with you to give you a better
idea if that would solve the problem for s390x as well.
--
Cheers,
David
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap()
2026-07-17 13:32 ` [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap() Alexander Gordeev
@ 2026-07-17 17:14 ` Kevin Brodsky
0 siblings, 0 replies; 7+ messages in thread
From: Kevin Brodsky @ 2026-07-17 17:14 UTC (permalink / raw)
To: Alexander Gordeev, David Hildenbrand, Chris Li, Gerald Schaefer,
Heiko Carstens, Christian Borntraeger, Claudio Imbrenda
Cc: linux-s390, linux-mm, linux-kernel, linux-sparse
On 17/07/2026 15:32, Alexander Gordeev wrote:
> Follow the pattern established by commit c33c794828f2 ("mm:
> ptep_get() conversion") and use proper accessors instead of
> direct pointer dereferences.
>
> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
> ---
> mm/madvise.c | 2 +-
> mm/mremap.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 77552b03d318..7d369b1ff8e5 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -1106,7 +1106,7 @@ static int guard_install_set_pte(unsigned long addr, unsigned long next,
> unsigned long *nr_pages = (unsigned long *)walk->private;
>
> /* Simply install a PTE marker, this causes segfault on access. */
> - *ptep = make_pte_marker(PTE_MARKER_GUARD);
> + set_pte(ptep, make_pte_marker(PTE_MARKER_GUARD));
AFAICT ptep is not pointing to a real page table entry, but a local copy
- see walk_pte_range_inner().
Such direct write to page tables are prevented by the pkeys-based
mechanism I proposed [1], and I can confirm that the guard-regions mm
kselftests do not cause any crash with that feature enabled.
- Kevin
[1] https://lore.kernel.org/all/20260526-kpkeys-v8-0-eaaacdacc67c@arm.com/
> (*nr_pages)++;
>
> return 0;
> diff --git a/mm/mremap.c b/mm/mremap.c
> index e9c8b1d05832..fc3b90274a57 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -264,7 +264,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
>
> for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE,
> new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) {
> - VM_WARN_ON_ONCE(!pte_none(*new_ptep));
> + VM_WARN_ON_ONCE(!pte_none(ptep_get(new_ptep)));
>
> nr_ptes = 1;
> max_nr_ptes = (old_end - old_addr) >> PAGE_SHIFT;
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-17 17:14 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17 13:32 [RFC PATCH 0/4] mm: introduce __ptent sparse attribute Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 1/4] mm: use proper PTE accessors in madvise() and mremap() Alexander Gordeev
2026-07-17 17:14 ` Kevin Brodsky
2026-07-17 13:32 ` [RFC PATCH 2/4] mm: introduce ptep_get_nopgtable() and set_pte_nopgtable() accessors Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 3/4] mm: introduce __ptent sparse attribute Alexander Gordeev
2026-07-17 13:32 ` [RFC PATCH 4/4] s390/mm: implement __ptent-aware pte_t type Alexander Gordeev
2026-07-17 14:53 ` [RFC PATCH 0/4] mm: introduce __ptent sparse attribute David Hildenbrand (Arm)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox