[RFC PATCH 08/10] mm: introduce and use linear_folio_page_index()

From: Lorenzo Stoakes

Date: Mon Jun 29 2026 - 11:15:00 EST


This function is, for now, a placeholder; it will be used in future to
determine whether to use the virtual page index or not, based on whether
the folio is anonymous or not.

Currently it simply wraps linear_page_index(), so this does not change
behaviour.

We update callers that will, once the change is introduced to track
anonymous folios by virtual page offset if MAP_PRIVATE file-backed, need to
determine which index to use based on folio type.

No functional change intended.

Signed-off-by: Lorenzo Stoakes <ljs@xxxxxxxxxx>
---
include/linux/pagemap.h | 18 ++++++++++++++++++
mm/huge_memory.c | 3 ++-
mm/migrate.c | 6 ++++--
mm/userfaultfd.c | 6 ++++--
4 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 6e0d719d639a..e2affa57dadd 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1146,6 +1146,24 @@ static inline pgoff_t linear_virt_page_index(const struct vm_area_struct *vma,
return pgoff;
}

+/**
+ * linear_folio_page_index() - Determine the absolute page offset of
+ * @address within @vma from @folio.
+ * @folio: The folio whose linear page index is sought.
+ * @vma: The VMA in which @address resides.
+ * @address: The address whose absolute page offset is required.
+ *
+ * For compatibility, currently identical to linear_page_index().
+ *
+ * Returns: The absolute page offset of @address within @vma.
+ */
+static inline pgoff_t linear_folio_page_index(const struct folio *folio,
+ const struct vm_area_struct *vma,
+ const unsigned long address)
+{
+ return linear_page_index(vma, address);
+}
+
struct wait_page_key {
struct folio *folio;
int bit_nr;
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e94f56487225..1b3456a9ff74 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2832,7 +2832,8 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
}

folio_move_anon_rmap(src_folio, dst_vma);
- src_folio->index = linear_page_index(dst_vma, dst_addr);
+ src_folio->index = linear_folio_page_index(src_folio, dst_vma,
+ dst_addr);

_dst_pmd = folio_mk_pmd(src_folio, dst_vma->vm_page_prot);
/* Follow mremap() behavior and treat the entry dirty after the move */
diff --git a/mm/migrate.c b/mm/migrate.c
index d9b23909d716..4250a56e09c0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -358,8 +358,10 @@ static bool remove_migration_pte(struct folio *folio,
unsigned long idx = 0;

/* pgoff is invalid for ksm pages, but they are never large */
- if (folio_test_large(folio) && !folio_test_hugetlb(folio))
- idx = linear_page_index(vma, pvmw.address) - pvmw.pgoff;
+ if (folio_test_large(folio) && !folio_test_hugetlb(folio)) {
+ idx += linear_folio_page_index(folio, vma, pvmw.address);
+ idx -= pvmw.pgoff;
+ }
new = folio_page(folio, idx);

#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index bf4518f4449d..9c6b1a678ca6 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1283,7 +1283,8 @@ static long move_present_ptes(struct mm_struct *mm,
}

folio_move_anon_rmap(src_folio, dst_vma);
- src_folio->index = linear_page_index(dst_vma, dst_addr);
+ src_folio->index = linear_folio_page_index(src_folio, dst_vma,
+ dst_addr);

orig_dst_pte = folio_mk_pte(src_folio, dst_vma->vm_page_prot);
/* Set soft dirty bit so userspace can notice the pte was moved */
@@ -1352,7 +1353,8 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
*/
if (src_folio) {
folio_move_anon_rmap(src_folio, dst_vma);
- src_folio->index = linear_page_index(dst_vma, dst_addr);
+ src_folio->index = linear_folio_page_index(src_folio, dst_vma,
+ dst_addr);
} else {
/*
* Check if the swap entry is cached after acquiring the src_pte
--
2.54.0