[PATCH v6 05/22] mm/swap: add a new function to check if a swap entry is in swap cached.

Nhat Pham
2026-05-05T15:39:09Z

Userfaultfd checks whether a swap entry is in swapcache. This is
currently done by directly looking at the swapfile's swap map - however,
the swap cached state will soon be managed at the virtual swap layer.
Abstract away this function.

Signed-off-by: Nhat Pham <nphamcs@gmail.com>
---
include/linux/swap.h | 6 ++++++
mm/swapfile.c | 15 +++++++++++++++
mm/userfaultfd.c | 3 +--
3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index 3da637b218ba..f91a442ac0e8 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -435,6 +435,7 @@ void free_swap_and_cache_nr(swp_entry_t entry, int nr);
int __swap_count(swp_entry_t entry);
bool swap_entry_swapped(struct swap_info_struct *si, swp_entry_t entry);
int swp_swapcount(swp_entry_t entry);
+bool is_swap_cached(swp_entry_t entry);

/* Swap cache API (mm/swap_state.c) */
static inline unsigned long total_swapcache_pages(void)
@@ -554,6 +555,11 @@ static inline int swp_swapcount(swp_entry_t entry)
return 0;
}

+static inline bool is_swap_cached(swp_entry_t entry)
+{
+ return false;
+}
+
static inline int folio_alloc_swap(struct folio *folio)
{
return -EINVAL;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 46da28c533bb..0471a965f222 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -194,6 +194,21 @@ static bool swap_only_has_cache(struct swap_info_struct *si,
return true;
}

+/**
+ * is_swap_cached - check if the swap entry is cached
+ * @entry: swap entry to check
+ *
+ * Check swap_map directly to minimize overhead, READ_ONCE is sufficient.
+ *
+ * Returns true if the swap entry is cached, false otherwise.
+ */
+bool is_swap_cached(swp_entry_t entry)
+{
+ struct swap_info_struct *si = __swap_entry_to_info(entry);
+
+ return READ_ONCE(si->swap_map[swp_offset(entry)]) & SWAP_HAS_CACHE;
+}
+
static bool swap_is_last_map(struct swap_info_struct *si,
unsigned long offset, int nr_pages, bool *has_cache)
{
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 25f89eba0438..98be764fb3ec 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1190,7 +1190,6 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
* Check if the swap entry is cached after acquiring the src_pte
* lock. Otherwise, we might miss a newly loaded swap cache folio.
*
- * Check swap_map directly to minimize overhead, READ_ONCE is sufficient.
* We are trying to catch newly added swap cache, the only possible case is
* when a folio is swapped in and out again staying in swap cache, using the
* same entry before the PTE check above. The PTL is acquired and released
@@ -1200,7 +1199,7 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
* cache, or during the tiny synchronization window between swap cache and
* swap_map, but it will be gone very quickly, worst result is retry jitters.
*/
- if (READ_ONCE(si->swap_map[swp_offset(entry)]) & SWAP_HAS_CACHE) {
+ if (is_swap_cached(entry)) {
double_pt_unlock(dst_ptl, src_ptl);
return -EAGAIN;
}
--
2.52.0