[RFC PATCH 01/12] mm: introduce and use pte_to_swp_entry_or_zero()

Lorenzo Stoakes
2025-10-24T07:42:51Z

When we check data in swap entries in the form of a predicate it is usually
the case that if the swap entry were zero, the predicate would evaluate as
false.

We can therefore simplify predicate checks where we first check to see if
the entry is indeed a swap entry before doing so by instead using a new
function which returns the zero swap entry (that is, swp_entry(0, 0))
should the entry be present.

The pte_none() case is also covered by this, as it will naturally evaluate
to swp_entry(0, 0).

We implement this via pte_to_swp_entry_or_zero(), which we then use in
is_pte_marker() and pte_marker_uffd_wp() both of which otherwise
unnecessarily utilise is_swap_pte().

We additionally update smaps_hugetlb_range() following the same pattern.

Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
fs/proc/task_mmu.c | 4 ++--
include/linux/swapops.h | 20 +++++++++++++++++++-
include/linux/userfaultfd_k.h | 7 +------
mm/madvise.c | 5 +++--
mm/page_vma_mapped.c | 5 +----
5 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index fc35a0543f01..a7c8501266f4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1230,8 +1230,8 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
if (pte_present(ptent)) {
folio = page_folio(pte_page(ptent));
present = true;
- } else if (is_swap_pte(ptent)) {
- swp_entry_t swpent = pte_to_swp_entry(ptent);
+ } else {
+ swp_entry_t swpent = pte_to_swp_entry_or_zero(ptent);

if (is_pfn_swap_entry(swpent))
folio = pfn_swap_entry_folio(swpent);
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 2687928a8146..24eaf8825c6b 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -139,6 +139,24 @@ static inline swp_entry_t pte_to_swp_entry(pte_t pte)
return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
}

+/**
+ * pte_to_swp_entry_or_zero() - Convert an arbitrary PTE entry to either its
+ * swap entry, or the zero swap entry if the PTE is either present or empty
+ * (none).
+ * @pte: The PTE entry we are evaluating.
+ *
+ * Returns: A valid swap entry or the zero swap entry if the PTE is present or
+ * none.
+ */
+static inline swp_entry_t pte_to_swp_entry_or_zero(pte_t pte)
+{
+ if (pte_present(pte))
+ return swp_entry(0, 0);
+
+ /* If none, this will return zero entry. */
+ return pte_to_swp_entry(pte);
+}
+
/*
* Convert the arch-independent representation of a swp_entry_t into the
* arch-dependent pte representation.
@@ -438,7 +456,7 @@ static inline pte_marker pte_marker_get(swp_entry_t entry)

static inline bool is_pte_marker(pte_t pte)
{
- return is_swap_pte(pte) && is_pte_marker_entry(pte_to_swp_entry(pte));
+ return is_pte_marker_entry(pte_to_swp_entry_or_zero(pte));
}

static inline pte_t make_pte_marker(pte_marker marker)
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index c0e716aec26a..4c65adff2e7a 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -447,12 +447,7 @@ static inline bool pte_marker_entry_uffd_wp(swp_entry_t entry)
static inline bool pte_marker_uffd_wp(pte_t pte)
{
#ifdef CONFIG_PTE_MARKER_UFFD_WP
- swp_entry_t entry;
-
- if (!is_swap_pte(pte))
- return false;
-
- entry = pte_to_swp_entry(pte);
+ swp_entry_t entry = pte_to_swp_entry_or_zero(pte);

return pte_marker_entry_uffd_wp(entry);
#else
diff --git a/mm/madvise.c b/mm/madvise.c
index fb1c86e630b6..f9f80b2e9d43 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1071,8 +1071,9 @@ static bool is_valid_guard_vma(struct vm_area_struct *vma, bool allow_locked)

static bool is_guard_pte_marker(pte_t ptent)
{
- return is_swap_pte(ptent) &&
- is_guard_swp_entry(pte_to_swp_entry(ptent));
+ const swp_entry_t entry = pte_to_swp_entry_or_zero(ptent);
+
+ return is_guard_swp_entry(entry);
}

static int guard_install_pud_entry(pud_t *pud, unsigned long addr,
diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c
index 137ce27ff68c..75a8fbb788b7 100644
--- a/mm/page_vma_mapped.c
+++ b/mm/page_vma_mapped.c
@@ -107,10 +107,7 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw, unsigned long pte_nr)
pte_t ptent = ptep_get(pvmw->pte);

if (pvmw->flags & PVMW_MIGRATION) {
- swp_entry_t entry;
- if (!is_swap_pte(ptent))
- return false;
- entry = pte_to_swp_entry(ptent);
+ swp_entry_t entry = pte_to_swp_entry_or_zero(ptent);

if (!is_migration_entry(entry))
return false;
--
2.51.0