AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/30 22:01 flow patch-triage
2m Args:
null

Results:
{
  "EnableConfigs": [
    "MEM_ALLOC_PROFILING",
    "TRANSPARENT_HUGEPAGE",
    "HUGETLB_PAGE",
    "USERFAULTFD",
    "MIGRATION"
  ],
  "FocusSymbols": [
    "split_folio_to_list",
    "folio_split",
    "move_pages_huge_pmd",
    "pgalloc_tag_split",
    "pgalloc_tag_swap",
    "isolate_folio_to_list",
    "shmem_read_mapping_page_gfp"
  ],
  "KMSANReasoning": "The patch series performs a mechanical refactoring across the core memory management subsystem (alloc_tag, compaction, filemap, gup, huge_memory, hugetlb, ksm, memory, migrate, page_alloc, rmap, etc.) replacing direct accesses to '\u0026folio-\u003epage' with the helper 'folio_page(folio, 0)', and replacing '\u0026folio-\u003epage' error returns with 'ERR_CAST(folio)'.\n\nAt the machine level, 'folio_page(folio, 0)' expands to '(\u0026(folio)-\u003epage + 0)', which is functionally and semantically identical to '\u0026folio-\u003epage'. The patch does not introduce new allocations, alter struct initialization or layout, modify memory copies to user space, or affect control flow based on uninitialized data. There are no risks of uninitialized memory access or kernel-to-user info-leaks. Any potential regression from page pointer manipulation would be caught by CONFIG_DEBUG_VM assertions, KASAN, or standard kernel debug facilities. A dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series modifies core memory management (mm/) subsystems, refactoring direct 'folio-\u003epage' references to 'folio_page(folio, 0)', correcting error returns (e.g. ERR_CAST in do_read_cache_page and shmem_read_mapping_page_gfp), altering list additions in compaction, and updating VM assertions (such as VM_BUG_ON_FOLIO). These modifications affect reachable MM paths including huge folio splitting, page migration, compaction, userfaultfd, and memory allocation profiling, making fuzzing valuable to detect regressions and violated invariants.",
  "WorthFuzzing": true
}

1/1 2026/09/30 22:01 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit e0b2f96dcac870e7cec69519979c25607faf5cb4\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Sep 30 22:01:20 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/mm/alloc_tag.c b/mm/alloc_tag.c\nindex 82e2c3448dcf2..c93efb224ce1b 100644\n--- a/mm/alloc_tag.c\n+++ b/mm/alloc_tag.c\n@@ -534,7 +534,7 @@ void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)\n \tif (!mem_alloc_profiling_enabled())\n \t\treturn;\n \n-\ttag = __pgalloc_tag_get(\u0026folio-\u003epage);\n+\ttag = __pgalloc_tag_get(folio_page(folio, 0));\n \tif (!tag)\n \t\treturn;\n \n@@ -560,16 +560,16 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old)\n \tif (!mem_alloc_profiling_enabled())\n \t\treturn;\n \n-\ttag_old = __pgalloc_tag_get(\u0026old-\u003epage);\n+\ttag_old = __pgalloc_tag_get(folio_page(old, 0));\n \tif (!tag_old)\n \t\treturn;\n-\ttag_new = __pgalloc_tag_get(\u0026new-\u003epage);\n+\ttag_new = __pgalloc_tag_get(folio_page(new, 0));\n \tif (!tag_new)\n \t\treturn;\n \n-\tif (!get_page_tag_ref(\u0026old-\u003epage, \u0026ref_old, \u0026handle_old))\n+\tif (!get_page_tag_ref(folio_page(old, 0), \u0026ref_old, \u0026handle_old))\n \t\treturn;\n-\tif (!get_page_tag_ref(\u0026new-\u003epage, \u0026ref_new, \u0026handle_new)) {\n+\tif (!get_page_tag_ref(folio_page(new, 0), \u0026ref_new, \u0026handle_new)) {\n \t\tput_page_tag_ref(handle_old);\n \t\treturn;\n \t}\ndiff --git a/mm/compaction.c b/mm/compaction.c\nindex f1b2060eb2016..d708d973250a4 100644\n--- a/mm/compaction.c\n+++ b/mm/compaction.c\n@@ -1845,7 +1845,6 @@ static void isolate_freepages(struct compact_control *cc)\n static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long data)\n {\n \tstruct compact_control *cc = (struct compact_control *)data;\n-\tstruct folio *dst;\n \tint order = folio_order(src);\n \tbool has_isolated_pages = false;\n \tint start_order;\n@@ -1878,15 +1877,13 @@ static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long da\n \n \t\tlist_add(\u0026freepage[size].lru, \u0026cc-\u003efreepages[start_order]);\n \t}\n-\tdst = (struct folio *)freepage;\n-\n-\tpost_alloc_hook(\u0026dst-\u003epage, order, __GFP_MOVABLE, ALLOC_DEFAULT);\n-\tset_page_refcounted(\u0026dst-\u003epage);\n+\tpost_alloc_hook(freepage, order, __GFP_MOVABLE, ALLOC_DEFAULT);\n+\tset_page_refcounted(freepage);\n \tif (order)\n-\t\tprep_compound_page(\u0026dst-\u003epage, order);\n+\t\tprep_compound_page(freepage, order);\n \tcc-\u003enr_freepages -= 1 \u003c\u003c order;\n \tcc-\u003enr_migratepages -= 1 \u003c\u003c order;\n-\treturn page_rmappable_folio(\u0026dst-\u003epage);\n+\treturn page_rmappable_folio(freepage);\n }\n \n static struct folio *compaction_alloc(struct folio *src, unsigned long data)\n@@ -1903,10 +1900,10 @@ static void compaction_free(struct folio *dst, unsigned long data)\n {\n \tstruct compact_control *cc = (struct compact_control *)data;\n \tint order = folio_order(dst);\n-\tstruct page *page = \u0026dst-\u003epage;\n+\tstruct page *page = folio_page(dst, 0);\n \n \tif (folio_put_testzero(dst) \u0026\u0026 free_pages_prepare(page, order)) {\n-\t\tlist_add(\u0026dst-\u003elru, \u0026cc-\u003efreepages[order]);\n+\t\tlist_add(\u0026page-\u003elru, \u0026cc-\u003efreepages[order]);\n \t\tcc-\u003enr_freepages += 1 \u003c\u003c order;\n \t}\n \tcc-\u003enr_migratepages += 1 \u003c\u003c order;\ndiff --git a/mm/filemap.c b/mm/filemap.c\nindex b74bc1e5015c6..02e0c2af594ca 100644\n--- a/mm/filemap.c\n+++ b/mm/filemap.c\n@@ -156,7 +156,7 @@ static void filemap_unaccount_folio(struct address_space *mapping,\n \tif (!IS_ENABLED(CONFIG_DEBUG_VM) \u0026\u0026 unlikely(folio_mapped(folio))) {\n \t\tpr_alert(\"BUG: Bad page cache in process %s  pfn:%05lx\\n\",\n \t\t\t current-\u003ecomm, folio_pfn(folio));\n-\t\tdump_page(\u0026folio-\u003epage, \"still mapped when deleted\");\n+\t\tdump_page(folio_page(folio, 0), \"still mapped when deleted\");\n \t\tdump_stack();\n \t\tadd_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);\n \n@@ -3888,7 +3888,7 @@ static vm_fault_t filemap_map_order0_folio(struct vm_fault *vmf,\n \t\tunsigned long *rss)\n {\n \tvm_fault_t ret = 0;\n-\tstruct page *page = \u0026folio-\u003epage;\n+\tstruct page *page = folio_page(folio, 0);\n \n \tif (PageHWPoison(page))\n \t\tgoto out;\n@@ -4239,7 +4239,7 @@ static struct page *do_read_cache_page(struct address_space *mapping,\n \n \tfolio = do_read_cache_folio(mapping, index, filler, file, gfp);\n \tif (IS_ERR(folio))\n-\t\treturn \u0026folio-\u003epage;\n+\t\treturn ERR_CAST(folio);\n \treturn folio_file_page(folio, index);\n }\n \ndiff --git a/mm/folio.c b/mm/folio.c\nindex 35e242b48870b..978565add078e 100644\n--- a/mm/folio.c\n+++ b/mm/folio.c\n@@ -103,7 +103,7 @@ void __folio_put(struct folio *folio)\n \tpage_cache_release(folio);\n \tfolio_unqueue_deferred_split(folio);\n \tmem_cgroup_uncharge(folio);\n-\tfree_frozen_pages(\u0026folio-\u003epage, folio_order(folio));\n+\tfree_frozen_pages(folio_page(folio, 0), folio_order(folio));\n }\n EXPORT_SYMBOL(__folio_put);\n \ndiff --git a/mm/gup.c b/mm/gup.c\nindex 8e9ef5ee7498c..1ce7ea5e7abb5 100644\n--- a/mm/gup.c\n+++ b/mm/gup.c\n@@ -59,10 +59,11 @@ static inline void sanity_check_pinned_pages(struct page **pages,\n \t\t    !folio_test_anon(folio))\n \t\t\tcontinue;\n \t\tif (!folio_test_large(folio) || folio_test_hugetlb(folio))\n-\t\t\tVM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(\u0026folio-\u003epage), folio);\n+\t\t\tVM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(folio_page(folio, 0)),\n+\t\t\t\t\t      folio);\n \t\telse\n \t\t\t/* Either a PTE-mapped or a PMD-mapped THP. */\n-\t\t\tVM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(\u0026folio-\u003epage) \u0026\u0026\n+\t\t\tVM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(folio_page(folio, 0)) \u0026\u0026\n \t\t\t\t\t     !PageAnonExclusive(page), page);\n \t}\n }\n@@ -2957,7 +2958,8 @@ static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp,\n \t\tgup_put_folio(folio, nr_pages, flags);\n \t\treturn 0;\n \t}\n-\tif (!pmd_write(orig) \u0026\u0026 gup_must_unshare(NULL, flags, \u0026folio-\u003epage)) {\n+\tif (!pmd_write(orig) \u0026\u0026\n+\t    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {\n \t\tgup_put_folio(folio, nr_pages, flags);\n \t\treturn 0;\n \t}\n@@ -2999,7 +3001,8 @@ static unsigned long gup_fast_pud_leaf(pud_t orig, pud_t *pudp,\n \t\treturn 0;\n \t}\n \n-\tif (!pud_write(orig) \u0026\u0026 gup_must_unshare(NULL, flags, \u0026folio-\u003epage)) {\n+\tif (!pud_write(orig) \u0026\u0026\n+\t    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {\n \t\tgup_put_folio(folio, nr_pages, flags);\n \t\treturn 0;\n \t}\ndiff --git a/mm/gup_test.c b/mm/gup_test.c\nindex ba74bf3f41048..337b58221c792 100644\n--- a/mm/gup_test.c\n+++ b/mm/gup_test.c\n@@ -59,13 +59,15 @@ static void verify_dma_pinned(unsigned int cmd, struct page **pages,\n \t\t\tif (WARN(!folio_maybe_dma_pinned(folio),\n \t\t\t\t \"pages[%lu] is NOT dma-pinned\\n\", i)) {\n \n-\t\t\t\tdump_page(\u0026folio-\u003epage, \"gup_test failure\");\n+\t\t\t\tdump_page(folio_page(folio, 0),\n+\t\t\t\t\t  \"gup_test failure\");\n \t\t\t\tbreak;\n \t\t\t} else if (cmd == PIN_LONGTERM_BENCHMARK \u0026\u0026\n \t\t\t\tWARN(!folio_is_longterm_pinnable(folio),\n \t\t\t\t     \"pages[%lu] is NOT pinnable but pinned\\n\",\n \t\t\t\t     i)) {\n-\t\t\t\tdump_page(\u0026folio-\u003epage, \"gup_test failure\");\n+\t\t\t\tdump_page(folio_page(folio, 0),\n+\t\t\t\t\t  \"gup_test failure\");\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/mm/huge_memory.c b/mm/huge_memory.c\nindex ddc631a388b93..58fbc4d4ddb8b 100644\n--- a/mm/huge_memory.c\n+++ b/mm/huge_memory.c\n@@ -1664,7 +1664,8 @@ static vm_fault_t insert_pmd(struct vm_area_struct *vma, unsigned long addr,\n \t\t\tentry = pmd_mkspecial(entry);\n \t\t} else {\n \t\t\tfolio_get(fop.folio);\n-\t\t\tfolio_add_file_rmap_pmd(fop.folio, \u0026fop.folio-\u003epage, vma);\n+\t\t\tfolio_add_file_rmap_pmd(fop.folio,\n+\t\t\t\t\t\tfolio_page(fop.folio, 0), vma);\n \t\t\tadd_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PMD_NR);\n \t\t}\n \t} else {\n@@ -1786,7 +1787,8 @@ static vm_fault_t insert_pud(struct vm_area_struct *vma, unsigned long addr,\n \t\tentry = folio_mk_pud(fop.folio, vma-\u003evm_page_prot);\n \n \t\tfolio_get(fop.folio);\n-\t\tfolio_add_file_rmap_pud(fop.folio, \u0026fop.folio-\u003epage, vma);\n+\t\tfolio_add_file_rmap_pud(fop.folio,\n+\t\t\t\t\tfolio_page(fop.folio, 0), vma);\n \t\tadd_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PUD_NR);\n \t} else {\n \t\tentry = pud_mkhuge(pfn_pud(fop.pfn, prot));\n@@ -1935,7 +1937,7 @@ static void copy_huge_non_present_pmd(\n \t\t * folio_try_dup_anon_rmap_pmd does not fail for\n \t\t * device private entries.\n \t\t */\n-\t\tfolio_try_dup_anon_rmap_pmd(src_folio, \u0026src_folio-\u003epage,\n+\t\tfolio_try_dup_anon_rmap_pmd(src_folio, folio_page(src_folio, 0),\n \t\t\t\t\t    dst_vma, src_vma);\n \t}\n \n@@ -2487,7 +2489,7 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,\n \n \t/* Present and device private folios are rmappable. */\n \tif (is_present || is_device_private)\n-\t\tfolio_remove_rmap_pmd(folio, \u0026folio-\u003epage, vma);\n+\t\tfolio_remove_rmap_pmd(folio, folio_page(folio, 0), vma);\n \n \tif (folio_test_anon(folio)) {\n \t\tadd_mm_counter(mm, MM_ANONPAGES, -HPAGE_PMD_NR);\n@@ -2572,7 +2574,7 @@ bool zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,\n \n \tspin_unlock(ptl);\n \tif (is_present \u0026\u0026 folio)\n-\t\ttlb_remove_page_size(tlb, \u0026folio-\u003epage, HPAGE_PMD_SIZE);\n+\t\ttlb_remove_page_size(tlb, folio_page(folio, 0), HPAGE_PMD_SIZE);\n \treturn true;\n }\n \n@@ -2947,7 +2949,7 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm\n \t}\n \tif (src_folio) {\n \t\tif (folio_maybe_dma_pinned(src_folio) ||\n-\t\t    !PageAnonExclusive(\u0026src_folio-\u003epage)) {\n+\t\t    !PageAnonExclusive(folio_page(src_folio, 0))) {\n \t\t\terr = -EBUSY;\n \t\t\tgoto unlock_ptls;\n \t\t}\n@@ -3709,7 +3711,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,\n \t * the flags from the original folio.\n \t */\n \tfor (i = new_nr_pages; i \u003c nr_pages; i += new_nr_pages) {\n-\t\tstruct page *new_head = \u0026folio-\u003epage + i;\n+\t\tstruct page *new_head = folio_page(folio, i);\n \t\t/*\n \t\t * Careful: new_folio is not a \"real\" folio before we cleared PageTail.\n \t\t * Don't pass it around before clear_compound_head().\n@@ -3806,7 +3808,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,\n \tif (new_order)\n \t\tfolio_set_order(folio, new_order);\n \telse\n-\t\tClearPageCompound(\u0026folio-\u003epage);\n+\t\tClearPageCompound(folio_page(folio, 0));\n }\n \n /**\n@@ -3896,7 +3898,7 @@ static int __split_frozen_folio(struct folio *folio, int new_order,\n \t\t}\n \n \t\tfolio_split_memcg_refs(folio, old_order, split_order);\n-\t\tsplit_page_owner(\u0026folio-\u003epage, old_order, split_order);\n+\t\tsplit_page_owner(folio_page(folio, 0), old_order, split_order);\n \t\tpgalloc_tag_split(folio, old_order, split_order);\n \t\t__split_folio_to_order(folio, old_order, split_order);\n \n@@ -4392,7 +4394,7 @@ int folio_split_unmapped(struct folio *folio, unsigned int new_order)\n \tVM_WARN_ON_ONCE_FOLIO(!folio_test_large(folio), folio);\n \tVM_WARN_ON_ONCE_FOLIO(!folio_test_anon(folio), folio);\n \n-\treturn __folio_freeze_split_anon(folio, new_order, \u0026folio-\u003epage,\n+\treturn __folio_freeze_split_anon(folio, new_order, folio_page(folio, 0),\n \t\t\t\t\t false, NULL, SPLIT_TYPE_UNIFORM);\n }\n \n@@ -4448,7 +4450,7 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list\n {\n \tstruct folio *folio = page_folio(page);\n \n-\treturn __folio_split(folio, new_order, \u0026folio-\u003epage, page, list,\n+\treturn __folio_split(folio, new_order, folio_page(folio, 0), page, list,\n \t\t\t     SPLIT_TYPE_UNIFORM);\n }\n \n@@ -4479,8 +4481,8 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list\n int folio_split(struct folio *folio, unsigned int new_order,\n \t\tstruct page *split_at, struct list_head *list)\n {\n-\treturn __folio_split(folio, new_order, split_at, \u0026folio-\u003epage, list,\n-\t\t\t     SPLIT_TYPE_NON_UNIFORM);\n+\treturn __folio_split(folio, new_order, split_at, folio_page(folio, 0),\n+\t\t\t     list, SPLIT_TYPE_NON_UNIFORM);\n }\n \n /**\n@@ -4512,7 +4514,7 @@ unsigned int min_order_for_split(struct folio *folio)\n \n int split_folio_to_list(struct folio *folio, struct list_head *list)\n {\n-\treturn split_huge_page_to_list_to_order(\u0026folio-\u003epage, list, 0);\n+\treturn split_huge_page_to_list_to_order(folio_page(folio, 0), list, 0);\n }\n \n /*\n@@ -5186,12 +5188,13 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct folio *folio\n \t\tif (!softleaf_is_migration_read(entry))\n \t\t\trmap_flags |= RMAP_EXCLUSIVE;\n \n-\t\tfolio_add_anon_rmap_pmd(folio, \u0026folio-\u003epage, vma, haddr, rmap_flags);\n+\t\tfolio_add_anon_rmap_pmd(folio, folio_page(folio, 0), vma,\n+\t\t\t\t\thaddr, rmap_flags);\n \t} else {\n-\t\tfolio_add_file_rmap_pmd(folio, \u0026folio-\u003epage, vma);\n+\t\tfolio_add_file_rmap_pmd(folio, folio_page(folio, 0), vma);\n \t}\n \tVM_WARN_ON_ONCE(pmd_write(pmde) \u0026\u0026 folio_test_anon(folio) \u0026\u0026\n-\t\t\t!PageAnonExclusive(\u0026folio-\u003epage));\n+\t\t\t!PageAnonExclusive(folio_page(folio, 0)));\n \tset_pmd_at(mm, haddr, pvmw-\u003epmd, pmde);\n \n \t/* No need to invalidate - it was non-present before */\ndiff --git a/mm/hugetlb.c b/mm/hugetlb.c\nindex a1b51251103b3..31ca8777ccbac 100644\n--- a/mm/hugetlb.c\n+++ b/mm/hugetlb.c\n@@ -1274,7 +1274,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,\n \t\tif (folio_test_hwpoison(folio))\n \t\t\tcontinue;\n \n-\t\tif (is_migrate_isolate_page(\u0026folio-\u003epage))\n+\t\tif (is_migrate_isolate_page(folio_page(folio, 0)))\n \t\t\tcontinue;\n \n \t\tlist_move(\u0026folio-\u003elru, \u0026h-\u003ehugepage_activelist);\n@@ -1511,7 +1511,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,\n \tif (folio_test_hugetlb_cma(folio))\n \t\thugetlb_cma_free_frozen_folio(folio);\n \telse\n-\t\tfree_frozen_pages(\u0026folio-\u003epage, folio_order(folio));\n+\t\tfree_frozen_pages(folio_page(folio, 0), folio_order(folio));\n }\n \n /*\n@@ -1701,7 +1701,7 @@ void free_huge_folio(struct folio *folio)\n \n \thugetlb_set_folio_subpool(folio, NULL);\n \tif (folio_test_anon(folio))\n-\t\t__ClearPageAnonExclusive(\u0026folio-\u003epage);\n+\t\t__ClearPageAnonExclusive(folio_page(folio, 0));\n \tfolio-\u003emapping = NULL;\n \trestore_reserve = folio_test_hugetlb_restore_reserve(folio);\n \tfolio_clear_hugetlb_restore_reserve(folio);\n@@ -3238,7 +3238,7 @@ static void __init hugetlb_folio_init_tail_vmemmap(struct folio *folio,\n \t */\n \tfor (pfn = head_pfn + start_page_number; pfn \u003c end_pfn; page++, pfn++) {\n \t\t__init_single_page(page, pfn, zone, nid);\n-\t\tprep_compound_tail(page, \u0026folio-\u003epage, order);\n+\t\tprep_compound_tail(page, folio_page(folio, 0), order);\n \t\tset_page_count(page, 0);\n \t}\n }\n@@ -3259,7 +3259,7 @@ static void __init hugetlb_folio_init_vmemmap(struct folio *folio,\n \tret = folio_ref_freeze(folio, 1);\n \tVM_BUG_ON(!ret);\n \thugetlb_folio_init_tail_vmemmap(folio, h, 1, nr_pages);\n-\tprep_compound_head(\u0026folio-\u003epage, huge_page_order(h));\n+\tprep_compound_head(folio_page(folio, 0), huge_page_order(h));\n }\n \n /*\n@@ -4004,7 +4004,8 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,\n \n \t\tlist_del(\u0026folio-\u003elru);\n \n-\t\tsplit_page_owner(\u0026folio-\u003epage, huge_page_order(src), huge_page_order(dst));\n+\t\tsplit_page_owner(folio_page(folio, 0), huge_page_order(src),\n+\t\t\t\t huge_page_order(dst));\n \t\tpgalloc_tag_split(folio, huge_page_order(src), huge_page_order(dst));\n \n \t\tfor (i = 0; i \u003c pages_per_huge_page(src); i += pages_per_huge_page(dst)) {\n@@ -5605,9 +5606,9 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)\n \t * be leaks between processes, for example, with FOLL_GET users.\n \t */\n \tif (folio_mapcount(old_folio) == 1 \u0026\u0026 folio_test_anon(old_folio)) {\n-\t\tif (!PageAnonExclusive(\u0026old_folio-\u003epage)) {\n+\t\tif (!PageAnonExclusive(folio_page(old_folio, 0))) {\n \t\t\tfolio_move_anon_rmap(old_folio, vma);\n-\t\t\tSetPageAnonExclusive(\u0026old_folio-\u003epage);\n+\t\t\tSetPageAnonExclusive(folio_page(old_folio, 0));\n \t\t}\n \t\tif (likely(!unshare))\n \t\t\tset_huge_ptep_maybe_writable(vma, vmf-\u003eaddress,\n@@ -5616,8 +5617,8 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)\n \t\tdelayacct_wpcopy_end();\n \t\treturn 0;\n \t}\n-\tVM_BUG_ON_PAGE(folio_test_anon(old_folio) \u0026\u0026\n-\t\t       PageAnonExclusive(\u0026old_folio-\u003epage), \u0026old_folio-\u003epage);\n+\tVM_BUG_ON_FOLIO(folio_test_anon(old_folio) \u0026\u0026\n+\t\t\tPageAnonExclusive(folio_page(old_folio, 0)), old_folio);\n \n \t/*\n \t * If the process that created a MAP_PRIVATE mapping is about to perform\ndiff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c\nindex 95fd2d190f0d2..e0fdd07cc6a99 100644\n--- a/mm/hugetlb_cma.c\n+++ b/mm/hugetlb_cma.c\n@@ -47,7 +47,8 @@ static phys_addr_t __init memblock_node_memory_size(int nid)\n void hugetlb_cma_free_frozen_folio(struct folio *folio)\n {\n \tWARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],\n-\t\t\t\t\t \u0026folio-\u003epage, folio_nr_pages(folio)));\n+\t\t\t\t\t folio_page(folio, 0),\n+\t\t\t\t\t folio_nr_pages(folio)));\n }\n \n struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,\ndiff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c\nindex 0057fa2a16a89..807c6bb23997e 100644\n--- a/mm/hugetlb_vmemmap.c\n+++ b/mm/hugetlb_vmemmap.c\n@@ -403,7 +403,7 @@ static int __hugetlb_vmemmap_restore_folio(const struct hstate *h,\n \tif (!folio_test_hugetlb_vmemmap_optimized(folio))\n \t\treturn 0;\n \n-\tvmemmap_start\t= (unsigned long)\u0026folio-\u003epage;\n+\tvmemmap_start\t= (unsigned long)folio_page(folio, 0);\n \tvmemmap_end\t= vmemmap_start + hugetlb_vmemmap_size(h);\n \n \tvmemmap_start\t+= HUGETLB_VMEMMAP_RESERVE_SIZE;\n@@ -531,11 +531,11 @@ static int __hugetlb_vmemmap_optimize_folio(const struct hstate *h,\n \t\tgoto out;\n \t}\n \n-\tcopy_page(page_to_virt(vmemmap_head), folio);\n+\tcopy_page(page_to_virt(vmemmap_head), folio_page(folio, 0));\n \tlist_add(\u0026vmemmap_head-\u003elru, vmemmap_pages);\n \tmemmap_pages_add(1);\n \n-\tvmemmap_start\t= (unsigned long)\u0026folio-\u003epage;\n+\tvmemmap_start\t= (unsigned long)folio_page(folio, 0);\n \tvmemmap_end\t= vmemmap_start + hugetlb_vmemmap_size(h);\n \n \t/*\n@@ -578,7 +578,7 @@ static int hugetlb_vmemmap_split_folio(const struct hstate *h, struct folio *fol\n \tif (!vmemmap_should_optimize_folio(h, folio))\n \t\treturn 0;\n \n-\tvmemmap_start\t= (unsigned long)\u0026folio-\u003epage;\n+\tvmemmap_start\t= (unsigned long)folio_page(folio, 0);\n \tvmemmap_end\t= vmemmap_start + hugetlb_vmemmap_size(h);\n \n \t/*\n@@ -610,7 +610,7 @@ static void __hugetlb_vmemmap_optimize_folios(struct hstate *h,\n \t\t\t * Already optimized by pre-HVO, just map the\n \t\t\t * mirrored tail page structs RO.\n \t\t\t */\n-\t\t\tspfn = (unsigned long)\u0026folio-\u003epage;\n+\t\t\tspfn = (unsigned long)folio_page(folio, 0);\n \t\t\tepfn = spfn + hugetlb_vmemmap_size(h);\n \t\t\tvmemmap_wrprotect_hvo(spfn, epfn, folio_nid(folio),\n \t\t\t\t\tHUGETLB_VMEMMAP_RESERVE_SIZE);\ndiff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c\nindex a11222572f978..127e5d75aa0d5 100644\n--- a/mm/hwpoison-inject.c\n+++ b/mm/hwpoison-inject.c\n@@ -131,7 +131,7 @@ static int hwpoison_inject(void *data, u64 val)\n \t * the targeted owner (or on a free page).\n \t * memory_failure() will redo the check reliably inside page lock.\n \t */\n-\terr = hwpoison_filter(\u0026folio-\u003epage);\n+\terr = hwpoison_filter(folio_page(folio, 0));\n \tif (err)\n \t\treturn 0;\n \ndiff --git a/mm/khugepaged.c b/mm/khugepaged.c\nindex 913086eaf17ba..63acb13f24ebd 100644\n--- a/mm/khugepaged.c\n+++ b/mm/khugepaged.c\n@@ -1793,7 +1793,7 @@ static void collect_mm_slot(struct mm_slot *slot)\n \n /* folio must be locked, and mmap_lock must be held */\n static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long addr,\n-\t\tpmd_t *pmdp, struct folio *folio, struct page *page)\n+\t\tpmd_t *pmdp, struct folio *folio)\n {\n \tstruct mm_struct *mm = vma-\u003evm_mm;\n \tstruct vm_fault vmf = {\n@@ -1821,7 +1821,7 @@ static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long a\n \t}\n \n \tvmf.pmd = pmdp;\n-\tif (do_set_pmd(\u0026vmf, folio, page))\n+\tif (do_set_pmd(\u0026vmf, folio, folio_page(folio, 0)))\n \t\treturn SCAN_FAIL;\n \n \tfolio_get(folio);\n@@ -2032,7 +2032,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign\n maybe_install_pmd:\n \t/* step 5: install pmd entry */\n \tresult = install_pmd\n-\t\t\t? set_huge_pmd(vma, haddr, pmd, folio, \u0026folio-\u003epage)\n+\t\t\t? set_huge_pmd(vma, haddr, pmd, folio)\n \t\t\t: SCAN_SUCCEED;\n \tgoto drop_folio;\n abort:\ndiff --git a/mm/ksm.c b/mm/ksm.c\nindex f33523a84a1a1..bb8c564d9ffb5 100644\n--- a/mm/ksm.c\n+++ b/mm/ksm.c\n@@ -1112,7 +1112,8 @@ struct ksm_stable_node *folio_stable_node(const struct folio *folio)\n static inline void folio_set_stable_node(struct folio *folio,\n \t\t\t\t\t struct ksm_stable_node *stable_node)\n {\n-\tVM_WARN_ON_FOLIO(folio_test_anon(folio) \u0026\u0026 PageAnonExclusive(\u0026folio-\u003epage), folio);\n+\tVM_WARN_ON_FOLIO(folio_test_anon(folio) \u0026\u0026\n+\t\t\t PageAnonExclusive(folio_page(folio, 0)), folio);\n \tWRITE_ONCE(folio-\u003emapping,\n \t\t   (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM));\n }\n@@ -1324,7 +1325,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,\n \tif (unlikely(!pte_present(entry)))\n \t\tgoto out_unlock;\n \n-\tanon_exclusive = PageAnonExclusive(\u0026folio-\u003epage);\n+\tanon_exclusive = PageAnonExclusive(folio_page(folio, 0));\n \tif (pte_write(entry) || pte_dirty(entry) ||\n \t    anon_exclusive || mm_tlb_flush_pending(mm)) {\n \t\tswapped = folio_test_swapcache(folio);\n@@ -1355,7 +1356,8 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,\n \n \t\t/* See folio_try_share_anon_rmap_pte(): clear PTE first. */\n \t\tif (anon_exclusive \u0026\u0026\n-\t\t    folio_try_share_anon_rmap_pte(folio, \u0026folio-\u003epage)) {\n+\t\t    folio_try_share_anon_rmap_pte(folio,\n+\t\t\t\t\t\t  folio_page(folio, 0))) {\n \t\t\tset_pte_at(mm, pvmw.address, pvmw.pte, entry);\n \t\t\tgoto out_unlock;\n \t\t}\n@@ -1893,7 +1895,7 @@ static struct folio *stable_tree_search(struct page *page)\n \t\t\tgoto again;\n \t\t}\n \n-\t\tret = memcmp_pages(page, \u0026tree_folio-\u003epage);\n+\t\tret = memcmp_pages(page, folio_page(tree_folio, 0));\n \t\tfolio_put(tree_folio);\n \n \t\tparent = *new;\n@@ -2100,7 +2102,8 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)\n \t\t\tgoto again;\n \t\t}\n \n-\t\tret = memcmp_pages(\u0026kfolio-\u003epage, \u0026tree_folio-\u003epage);\n+\t\tret = memcmp_pages(folio_page(kfolio, 0),\n+\t\t\t\t   folio_page(tree_folio, 0));\n \t\tfolio_put(tree_folio);\n \n \t\tparent = *new;\n@@ -2333,7 +2336,8 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite\n \t\tif (kfolio == ERR_PTR(-EBUSY))\n \t\t\treturn;\n \n-\t\terr = try_to_merge_with_ksm_page(rmap_item, page, \u0026kfolio-\u003epage);\n+\t\terr = try_to_merge_with_ksm_page(rmap_item, page,\n+\t\t\t\t\t\t folio_page(kfolio, 0));\n \t\tif (!err) {\n \t\t\t/*\n \t\t\t * The page was successfully merged:\ndiff --git a/mm/memory-failure.c b/mm/memory-failure.c\nindex 0c96eb5119976..771a75eb55050 100644\n--- a/mm/memory-failure.c\n+++ b/mm/memory-failure.c\n@@ -1400,7 +1400,7 @@ static int __get_hwpoison_page(struct page *page, unsigned long flags)\n \t * unsupported type of folio in order to reduce the risk of unexpected\n \t * races caused by taking a folio refcount.\n \t */\n-\tif (!HWPoisonHandlable(\u0026folio-\u003epage, flags))\n+\tif (!HWPoisonHandlable(folio_page(folio, 0), flags))\n \t\treturn -EBUSY;\n \n \tif (folio_try_get(folio)) {\n@@ -1777,7 +1777,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,\n \tif (!cookie)\n \t\treturn -EBUSY;\n \n-\tif (hwpoison_filter(\u0026folio-\u003epage)) {\n+\tif (hwpoison_filter(folio_page(folio, 0))) {\n \t\trc = -EOPNOTSUPP;\n \t\tgoto unlock;\n \t}\n@@ -1799,7 +1799,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,\n \t * Use this flag as an indication that the dax page has been\n \t * remapped UC to prevent speculative consumption of poison.\n \t */\n-\tSetPageHWPoison(\u0026folio-\u003epage);\n+\tfolio_set_hwpoison(folio);\n \n \t/*\n \t * Unlike System-RAM there is no possibility to swap in a\n@@ -1808,7 +1808,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,\n \t * SIGBUS (i.e. MF_MUST_KILL)\n \t */\n \tflags |= MF_ACTION_REQUIRED | MF_MUST_KILL;\n-\tcollect_procs(folio, \u0026folio-\u003epage, \u0026to_kill, true);\n+\tcollect_procs(folio, folio_page(folio, 0), \u0026to_kill, true);\n \n \tunmap_and_kill(\u0026to_kill, pfn, folio-\u003emapping, folio-\u003eindex, flags);\n unlock:\ndiff --git a/mm/memory.c b/mm/memory.c\nindex 1f83a26f87333..e7c86e7301923 100644\n--- a/mm/memory.c\n+++ b/mm/memory.c\n@@ -1098,7 +1098,8 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma\n \t * over and copy the page \u0026 arm it.\n \t */\n \n-\tif (copy_mc_user_highpage(\u0026new_folio-\u003epage, page, addr, src_vma))\n+\tif (copy_mc_user_highpage(folio_page(new_folio, 0), page, addr,\n+\t\t\t\t  src_vma))\n \t\treturn -EHWPOISON;\n \n \t*prealloc = NULL;\n@@ -4035,7 +4036,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)\n \tif (!pfn_is_zero) {\n \t\tint err;\n \n-\t\terr = __wp_page_copy_user(\u0026new_folio-\u003epage, vmf-\u003epage, vmf);\n+\t\terr = __wp_page_copy_user(folio_page(new_folio, 0), vmf-\u003epage,\n+\t\t\t\t\t  vmf);\n \t\tif (err) {\n \t\t\t/*\n \t\t\t * COW failed, if the fault was solved by other,\n@@ -4051,7 +4053,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)\n \t\t\tdelayacct_wpcopy_end();\n \t\t\treturn err == -EHWPOISON ? VM_FAULT_HWPOISON : 0;\n \t\t}\n-\t\tkmsan_copy_page_meta(\u0026new_folio-\u003epage, vmf-\u003epage);\n+\t\tkmsan_copy_page_meta(folio_page(new_folio, 0), vmf-\u003epage);\n \t}\n \n \t__folio_mark_uptodate(new_folio);\n@@ -5105,7 +5107,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)\n \t\tptep = folio_ptep;\n \t\tnr_pages = nr;\n \t\tentry = folio-\u003eswap;\n-\t\tpage = \u0026folio-\u003epage;\n+\t\tpage = folio_page(folio, 0);\n \t}\n \n check_folio:\n@@ -5659,7 +5661,7 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa\n \n \tif (!is_pmd_order(folio_order(folio)))\n \t\treturn ret;\n-\tpage = \u0026folio-\u003epage;\n+\tpage = folio_page(folio, 0);\n \n \t/*\n \t * Just backoff if any subpage of a THP is corrupted otherwise\n@@ -5870,7 +5872,7 @@ vm_fault_t finish_fault(struct vm_fault *vmf)\n \t\t} else {\n \t\t\t/* Now we can set mappings for the whole large folio. */\n \t\t\taddr = vmf-\u003eaddress - idx * PAGE_SIZE;\n-\t\t\tpage = \u0026folio-\u003epage;\n+\t\t\tpage = folio_page(folio, 0);\n \t\t}\n \t}\n \n@@ -6055,7 +6057,7 @@ static vm_fault_t do_cow_fault(struct vm_fault *vmf)\n \tif (!folio)\n \t\treturn VM_FAULT_OOM;\n \n-\tvmf-\u003ecow_page = \u0026folio-\u003epage;\n+\tvmf-\u003ecow_page = folio_page(folio, 0);\n \n \tret = __do_fault(vmf);\n \tif (unlikely(ret \u0026 (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))\ndiff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c\nindex 796af1028ee23..47bf3b5d3ff27 100644\n--- a/mm/memory_hotplug.c\n+++ b/mm/memory_hotplug.c\n@@ -1952,7 +1952,7 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)\n \t\t\t\tif (__ratelimit(\u0026migrate_rs)) {\n \t\t\t\t\tpr_warn(\"migrating pfn %lx failed ret:%d\\n\",\n \t\t\t\t\t\tfolio_pfn(folio), ret);\n-\t\t\t\t\tdump_page(\u0026folio-\u003epage,\n+\t\t\t\t\tdump_page(folio_page(folio, 0),\n \t\t\t\t\t\t  \"migration failure\");\n \t\t\t\t}\n \t\t\t}\ndiff --git a/mm/memremap.c b/mm/memremap.c\nindex accba23aef28c..70cfd3f05a257 100644\n--- a/mm/memremap.c\n+++ b/mm/memremap.c\n@@ -467,7 +467,7 @@ void free_zone_device_folio(struct folio *folio)\n \t\tbreak;\n \n \tcase MEMORY_DEVICE_FS_DAX:\n-\t\twake_up_var(\u0026folio-\u003epage);\n+\t\twake_up_var(folio_page(folio, 0));\n \t\tbreak;\n \n \tcase MEMORY_DEVICE_PCI_P2PDMA:\ndiff --git a/mm/migrate.c b/mm/migrate.c\nindex 7bdcdb57652f8..b027c938d8301 100644\n--- a/mm/migrate.c\n+++ b/mm/migrate.c\n@@ -266,8 +266,8 @@ void putback_movable_pages(struct list_head *l)\n \t\t\tcontinue;\n \t\t}\n \t\tlist_del(\u0026folio-\u003elru);\n-\t\tif (unlikely(page_has_movable_ops(\u0026folio-\u003epage))) {\n-\t\t\tputback_movable_ops_page(\u0026folio-\u003epage);\n+\t\tif (unlikely(page_has_movable_ops(folio_page(folio, 0)))) {\n+\t\t\tputback_movable_ops_page(folio_page(folio, 0));\n \t\t} else {\n \t\t\tnode_stat_mod_folio(folio, NR_ISOLATED_ANON +\n \t\t\t\t\tfolio_is_file_lru(folio), -folio_nr_pages(folio));\n@@ -282,8 +282,8 @@ bool isolate_folio_to_list(struct folio *folio, struct list_head *list)\n \tif (folio_test_hugetlb(folio))\n \t\treturn folio_isolate_hugetlb(folio, list);\n \n-\tif (page_has_movable_ops(\u0026folio-\u003epage)) {\n-\t\tif (!isolate_movable_ops_page(\u0026folio-\u003epage,\n+\tif (page_has_movable_ops(folio_page(folio, 0))) {\n+\t\tif (!isolate_movable_ops_page(folio_page(folio, 0),\n \t\t\t\t\t      ISOLATE_UNEVICTABLE))\n \t\t\treturn false;\n \t} else {\n@@ -1199,7 +1199,8 @@ static void migrate_folio_undo_dst(struct folio *dst, bool locked,\n static void migrate_folio_done(struct folio *src,\n \t\t\t       enum migrate_reason reason)\n {\n-\tif (likely(!page_has_movable_ops(\u0026src-\u003epage)) \u0026\u0026 reason != MR_DEMOTION)\n+\tif (likely(!page_has_movable_ops(folio_page(src, 0))) \u0026\u0026\n+\t    reason != MR_DEMOTION)\n \t\tmod_node_page_state(folio_pgdat(src), NR_ISOLATED_ANON +\n \t\t\t\t    folio_is_file_lru(src), -folio_nr_pages(src));\n \n@@ -1308,7 +1309,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,\n \t\tgoto out;\n \tdst_locked = true;\n \n-\tif (unlikely(page_has_movable_ops(\u0026src-\u003epage))) {\n+\tif (unlikely(page_has_movable_ops(folio_page(src, 0)))) {\n \t\t__migrate_folio_record(dst, old_folio_state, anon_vma);\n \t\treturn 0;\n \t}\n@@ -1375,8 +1376,9 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,\n \tprev = dst-\u003elru.prev;\n \tlist_del(\u0026dst-\u003elru);\n \n-\tif (unlikely(page_has_movable_ops(\u0026src-\u003epage))) {\n-\t\trc = migrate_movable_ops_page(\u0026dst-\u003epage, \u0026src-\u003epage, mode);\n+\tif (unlikely(page_has_movable_ops(folio_page(src, 0)))) {\n+\t\trc = migrate_movable_ops_page(folio_page(dst, 0),\n+\t\t\t\t\t      folio_page(src, 0), mode);\n \t\tif (rc)\n \t\t\tgoto out;\n \t\tgoto out_unlock_both;\n@@ -1903,7 +1905,7 @@ static int migrate_pages_batch(struct list_head *from,\n \t\t\t * If we are holding the last folio reference, the folio\n \t\t\t * was freed from under us, so just drop our reference.\n \t\t\t */\n-\t\t\tif (likely(!page_has_movable_ops(\u0026folio-\u003epage)) \u0026\u0026\n+\t\t\tif (likely(!page_has_movable_ops(folio_page(folio, 0))) \u0026\u0026\n \t\t\t    folio_ref_count(folio) == 1) {\n \t\t\t\tfolio_clear_active(folio);\n \t\t\t\tfolio_clear_unevictable(folio);\ndiff --git a/mm/page_alloc.c b/mm/page_alloc.c\nindex 641384085e341..870ff378d61d2 100644\n--- a/mm/page_alloc.c\n+++ b/mm/page_alloc.c\n@@ -3006,17 +3006,18 @@ void free_unref_folios(struct folio_batch *folios)\n \t/* Prepare folios for freeing */\n \tfor (i = 0, j = 0; i \u003c folios-\u003enr; i++) {\n \t\tstruct folio *folio = folios-\u003efolios[i];\n+\t\tstruct page *page = folio_page(folio, 0);\n \t\tunsigned long pfn = folio_pfn(folio);\n \t\tunsigned int order = folio_order(folio);\n \n-\t\tif (!__free_pages_prepare(\u0026folio-\u003epage, order, FPI_NONE))\n+\t\tif (!__free_pages_prepare(page, order, FPI_NONE))\n \t\t\tcontinue;\n \t\t/*\n \t\t * Free orders not handled on the PCP directly to the\n \t\t * allocator.\n \t\t */\n \t\tif (!pcp_allowed_order(order)) {\n-\t\t\tfree_one_page(folio_zone(folio), \u0026folio-\u003epage,\n+\t\t\tfree_one_page(folio_zone(folio), page,\n \t\t\t\t      pfn, order, FPI_NONE);\n \t\t\tcontinue;\n \t\t}\n@@ -3029,13 +3030,14 @@ void free_unref_folios(struct folio_batch *folios)\n \n \tfor (i = 0; i \u003c folios-\u003enr; i++) {\n \t\tstruct folio *folio = folios-\u003efolios[i];\n+\t\tstruct page *page = folio_page(folio, 0);\n \t\tstruct zone *zone = folio_zone(folio);\n \t\tunsigned long pfn = folio_pfn(folio);\n \t\tunsigned int order = (unsigned long)folio-\u003eprivate;\n \t\tint migratetype;\n \n \t\tfolio-\u003eprivate = NULL;\n-\t\tmigratetype = get_pfnblock_migratetype(\u0026folio-\u003epage, pfn);\n+\t\tmigratetype = get_pfnblock_migratetype(page, pfn);\n \n \t\t/* Different zone requires a different pcp lock */\n \t\tif (zone != locked_zone ||\n@@ -3051,7 +3053,7 @@ void free_unref_folios(struct folio_batch *folios)\n \t\t\t * allocator, see comment in free_frozen_pages.\n \t\t\t */\n \t\t\tif (is_migrate_isolate(migratetype)) {\n-\t\t\t\tfree_one_page(zone, \u0026folio-\u003epage, pfn,\n+\t\t\t\tfree_one_page(zone, page, pfn,\n \t\t\t\t\t      order, FPI_NONE);\n \t\t\t\tcontinue;\n \t\t\t}\n@@ -3062,7 +3064,7 @@ void free_unref_folios(struct folio_batch *folios)\n \t\t\t */\n \t\t\tpcp = pcp_spin_trylock(zone-\u003eper_cpu_pageset);\n \t\t\tif (unlikely(!pcp)) {\n-\t\t\t\tfree_one_page(zone, \u0026folio-\u003epage, pfn,\n+\t\t\t\tfree_one_page(zone, page, pfn,\n \t\t\t\t\t      order, FPI_NONE);\n \t\t\t\tcontinue;\n \t\t\t}\n@@ -3076,9 +3078,9 @@ void free_unref_folios(struct folio_batch *folios)\n \t\tif (unlikely(migratetype \u003e= MIGRATE_PCPTYPES))\n \t\t\tmigratetype = MIGRATE_MOVABLE;\n \n-\t\ttrace_mm_page_free_batched(\u0026folio-\u003epage);\n-\t\tif (!free_frozen_page_commit(zone, pcp, \u0026folio-\u003epage,\n-\t\t\t\tmigratetype, order, FPI_NONE)) {\n+\t\ttrace_mm_page_free_batched(page);\n+\t\tif (!free_frozen_page_commit(zone, pcp, page,\n+\t\t\t\t\t     migratetype, order, FPI_NONE)) {\n \t\t\tpcp = NULL;\n \t\t\tlocked_zone = NULL;\n \t\t}\ndiff --git a/mm/page_isolation.c b/mm/page_isolation.c\nindex 5aaad037384e4..29c9e108b2e59 100644\n--- a/mm/page_isolation.c\n+++ b/mm/page_isolation.c\n@@ -47,7 +47,7 @@ bool page_is_unmovable(struct zone *zone, struct page *page,\n \t\tunsigned long nr_pages, pfn;\n \t\tunsigned int order;\n \n-\t\torder = compound_order(\u0026folio-\u003epage);\n+\t\torder = compound_order(folio_page(folio, 0));\n \t\tif (order \u003e MAX_FOLIO_ORDER)\n \t\t\treturn true;\n \ndiff --git a/mm/page_owner.c b/mm/page_owner.c\nindex cfc31c92d7657..39c381699a633 100644\n--- a/mm/page_owner.c\n+++ b/mm/page_owner.c\n@@ -365,7 +365,7 @@ noinline void __set_page_owner(struct page *page, unsigned short order,\n \n void __folio_set_owner_migrate_reason(struct folio *folio, enum migrate_reason reason)\n {\n-\tstruct page_ext *page_ext = page_ext_get(\u0026folio-\u003epage);\n+\tstruct page_ext *page_ext = page_ext_get(folio_page(folio, 0));\n \tstruct page_owner *page_owner;\n \n \tif (unlikely(!page_ext))\n@@ -398,14 +398,14 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)\n \tstruct page_owner *new_page_owner;\n \tdepot_stack_handle_t migrate_handle;\n \n-\tpage_ext = page_ext_get(\u0026old-\u003epage);\n+\tpage_ext = page_ext_get(folio_page(old, 0));\n \tif (unlikely(!page_ext))\n \t\treturn;\n \n \told_page_owner = get_page_owner(page_ext);\n \tpage_ext_put(page_ext);\n \n-\tpage_ext = page_ext_get(\u0026newfolio-\u003epage);\n+\tpage_ext = page_ext_get(folio_page(newfolio, 0));\n \tif (unlikely(!page_ext))\n \t\treturn;\n \n@@ -413,7 +413,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)\n \tpage_ext_put(page_ext);\n \n \tmigrate_handle = new_page_owner-\u003ehandle;\n-\t__update_page_owner_handle(\u0026newfolio-\u003epage, old_page_owner-\u003ehandle,\n+\t__update_page_owner_handle(folio_page(newfolio, 0),\n+\t\t\t\t   old_page_owner-\u003ehandle,\n \t\t\t\t   old_page_owner-\u003eorder, old_page_owner-\u003egfp_mask,\n \t\t\t\t   old_page_owner-\u003elast_migrate_reason,\n \t\t\t\t   old_page_owner-\u003ets_nsec, old_page_owner-\u003epid,\n@@ -423,7 +424,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)\n \t * will be freed after migration. Keep them until then as they may be\n \t * useful.\n \t */\n-\t__update_page_owner_free_handle(\u0026newfolio-\u003epage, 0, old_page_owner-\u003eorder,\n+\t__update_page_owner_free_handle(folio_page(newfolio, 0), 0,\n+\t\t\t\t\told_page_owner-\u003eorder,\n \t\t\t\t\told_page_owner-\u003efree_pid,\n \t\t\t\t\told_page_owner-\u003efree_tgid,\n \t\t\t\t\told_page_owner-\u003efree_ts_nsec);\n@@ -433,7 +435,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)\n \t * when subtracting those pages from the stack.\n \t */\n \trcu_read_lock();\n-\tfor_each_page_ext(\u0026old-\u003epage, 1 \u003c\u003c new_page_owner-\u003eorder, page_ext, iter) {\n+\tfor_each_page_ext(folio_page(old, 0), 1 \u003c\u003c new_page_owner-\u003eorder,\n+\t\t\t  page_ext, iter) {\n \t\told_page_owner = get_page_owner(page_ext);\n \t\told_page_owner-\u003ehandle = migrate_handle;\n \t}\ndiff --git a/mm/rmap.c b/mm/rmap.c\nindex fbd66a2823b7b..cd1cf570c770d 100644\n--- a/mm/rmap.c\n+++ b/mm/rmap.c\n@@ -1668,7 +1668,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,\n \t\t/* increment count (starts at -1) */\n \t\tatomic_set(\u0026folio-\u003e_mapcount, 0);\n \t\tif (exclusive)\n-\t\t\tSetPageAnonExclusive(\u0026folio-\u003epage);\n+\t\t\tSetPageAnonExclusive(folio_page(folio, 0));\n \t} else if (!folio_test_pmd_mappable(folio)) {\n \t\tint i;\n \n@@ -1694,7 +1694,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,\n \t\tif (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))\n \t\t\tatomic_set(\u0026folio-\u003e_nr_pages_mapped, ENTIRELY_MAPPED);\n \t\tif (exclusive)\n-\t\t\tSetPageAnonExclusive(\u0026folio-\u003epage);\n+\t\t\tSetPageAnonExclusive(folio_page(folio, 0));\n \t\tnr_pmdmapped = nr;\n \t}\n \n@@ -3187,9 +3187,9 @@ void hugetlb_add_anon_rmap(struct folio *folio, struct vm_area_struct *vma,\n \tatomic_inc(\u0026folio-\u003e_entire_mapcount);\n \tatomic_inc(\u0026folio-\u003e_large_mapcount);\n \tif (flags \u0026 RMAP_EXCLUSIVE)\n-\t\tSetPageAnonExclusive(\u0026folio-\u003epage);\n+\t\tSetPageAnonExclusive(folio_page(folio, 0));\n \tVM_WARN_ON_FOLIO(folio_entire_mapcount(folio) \u003e 1 \u0026\u0026\n-\t\t\t PageAnonExclusive(\u0026folio-\u003epage), folio);\n+\t\t\t PageAnonExclusive(folio_page(folio, 0)), folio);\n }\n \n void hugetlb_add_new_anon_rmap(struct folio *folio,\n@@ -3203,6 +3203,6 @@ void hugetlb_add_new_anon_rmap(struct folio *folio,\n \tatomic_set(\u0026folio-\u003e_large_mapcount, 0);\n \tfolio_clear_hugetlb_restore_reserve(folio);\n \t__folio_set_anon(folio, vma, address, true);\n-\tSetPageAnonExclusive(\u0026folio-\u003epage);\n+\tSetPageAnonExclusive(folio_page(folio, 0));\n }\n #endif /* CONFIG_HUGETLB_PAGE */\ndiff --git a/mm/shmem.c b/mm/shmem.c\nindex ae08cff4500c3..940af0067ddf4 100644\n--- a/mm/shmem.c\n+++ b/mm/shmem.c\n@@ -6192,7 +6192,7 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,\n \tstruct page *page;\n \n \tif (IS_ERR(folio))\n-\t\treturn \u0026folio-\u003epage;\n+\t\treturn ERR_CAST(folio);\n \n \tpage = folio_file_page(folio, index);\n \tif (PageHWPoison(page)) {\ndiff --git a/mm/userfaultfd.c b/mm/userfaultfd.c\nindex 3c7fd39deb137..a39d7d40a76b0 100644\n--- a/mm/userfaultfd.c\n+++ b/mm/userfaultfd.c\n@@ -565,7 +565,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,\n \t\t\t\tgoto err_folio_put;\n \t\t}\n \t} else if (uffd_flags_mode_is(flags, MFILL_ATOMIC_ZEROPAGE)) {\n-\t\tclear_user_highpage(\u0026folio-\u003epage, state-\u003edst_addr);\n+\t\tclear_user_highpage(folio_page(folio, 0), state-\u003edst_addr);\n \t} else {\n \t\tVM_WARN_ONCE(1, \"Unknown UFFDIO operation, flags: %x\", flags);\n \t}\n@@ -584,7 +584,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,\n \t}\n \n \tret = mfill_atomic_install_pte(state-\u003epmd, state-\u003evma, dst_addr,\n-\t\t\t\t       \u0026folio-\u003epage, flags);\n+\t\t\t\t       folio_page(folio, 0), flags);\n \tif (ret)\n \t\tgoto err_filemap_remove;\n \n@@ -1268,7 +1268,8 @@ static struct folio *check_ptes_for_batched_move(struct vm_area_struct *src_vma,\n \tfolio = vm_normal_folio(src_vma, src_addr, orig_src_pte);\n \tif (!folio || !folio_trylock(folio))\n \t\treturn NULL;\n-\tif (!PageAnonExclusive(\u0026folio-\u003epage) || folio_test_large(folio)) {\n+\tif (!PageAnonExclusive(folio_page(folio, 0)) ||\n+\t    folio_test_large(folio)) {\n \t\tfolio_unlock(folio);\n \t\treturn NULL;\n \t}\n@@ -1306,7 +1307,7 @@ static long move_present_ptes(struct mm_struct *mm,\n \t}\n \tif (folio_test_large(src_folio) ||\n \t    folio_maybe_dma_pinned(src_folio) ||\n-\t    !PageAnonExclusive(\u0026src_folio-\u003epage)) {\n+\t    !PageAnonExclusive(folio_page(src_folio, 0))) {\n \t\terr = -EBUSY;\n \t\tgoto out;\n \t}\n@@ -1590,7 +1591,8 @@ static long move_pages_ptes(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd\n \t\t\t}\n \n \t\t\tfolio = vm_normal_folio(src_vma, src_addr, orig_src_pte);\n-\t\t\tif (!folio || !PageAnonExclusive(\u0026folio-\u003epage)) {\n+\t\t\tif (!folio ||\n+\t\t\t    !PageAnonExclusive(folio_page(folio, 0))) {\n \t\t\t\tspin_unlock(src_ptl);\n \t\t\t\tret = -EBUSY;\n \t\t\t\tgoto out;\n@@ -2072,7 +2074,7 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,\n \t\t\t\t\tstruct folio *folio = pmd_folio(*src_pmd);\n \n \t\t\t\t\tif (!is_huge_zero_folio(folio) \u0026\u0026\n-\t\t\t\t\t    !PageAnonExclusive(\u0026folio-\u003epage)) {\n+\t\t\t\t\t    !PageAnonExclusive(folio_page(folio, 0))) {\n \t\t\t\t\t\tspin_unlock(ptl);\n \t\t\t\t\t\terr = -EBUSY;\n \t\t\t\t\t\tbreak;\ndiff --git a/mm/vmscan.c b/mm/vmscan.c\nindex 91295070ca336..150ffeec3d478 100644\n--- a/mm/vmscan.c\n+++ b/mm/vmscan.c\n@@ -1709,7 +1709,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,\n \n \tlist_for_each_entry_safe(folio, next, folio_list, lru) {\n \t\t/* TODO: these pages should not even appear in this list. */\n-\t\tif (page_has_movable_ops(\u0026folio-\u003epage))\n+\t\tif (page_has_movable_ops(folio_page(folio, 0)))\n \t\t\tcontinue;\n \t\tif (!folio_test_hugetlb(folio) \u0026\u0026 folio_is_file_lru(folio) \u0026\u0026\n \t\t    !folio_test_dirty(folio) \u0026\u0026 !folio_test_unevictable(folio)) {\n"
}

2/1 2026/09/30 22:01 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "MEM_ALLOC_PROFILING",
    "TRANSPARENT_HUGEPAGE",
    "HUGETLB_PAGE",
    "USERFAULTFD",
    "MIGRATION"
  ],
  "FocusSymbols": [
    "split_folio_to_list",
    "folio_split",
    "move_pages_huge_pmd",
    "pgalloc_tag_split",
    "pgalloc_tag_swap",
    "isolate_folio_to_list",
    "shmem_read_mapping_page_gfp"
  ],
  "Reasoning": "The patch series modifies core memory management (mm/) subsystems, refactoring direct 'folio-\u003epage' references to 'folio_page(folio, 0)', correcting error returns (e.g. ERR_CAST in do_read_cache_page and shmem_read_mapping_page_gfp), altering list additions in compaction, and updating VM assertions (such as VM_BUG_ON_FOLIO). These modifications affect reachable MM paths including huge folio splitting, page migration, compaction, userfaultfd, and memory allocation profiling, making fuzzing valuable to detect regressions and violated invariants.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit e0b2f96dcac870e7cec69519979c25607faf5cb4
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Sep 30 22:01:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index 82e2c3448dcf2..c93efb224ce1b 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -534,7 +534,7 @@ void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)
 	if (!mem_alloc_profiling_enabled())
 		return;
 
-	tag = __pgalloc_tag_get(&folio->page);
+	tag = __pgalloc_tag_get(folio_page(folio, 0));
 	if (!tag)
 		return;
 
@@ -560,16 +560,16 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old)
 	if (!mem_alloc_profiling_enabled())
 		return;
 
-	tag_old = __pgalloc_tag_get(&old->page);
+	tag_old = __pgalloc_tag_get(folio_page(old, 0));
 	if (!tag_old)
 		return;
-	tag_new = __pgalloc_tag_get(&new->page);
+	tag_new = __pgalloc_tag_get(folio_page(new, 0));
 	if (!tag_new)
 		return;
 
-	if (!get_page_tag_ref(&old->page, &ref_old, &handle_old))
+	if (!get_page_tag_ref(folio_page(old, 0), &ref_old, &handle_old))
 		return;
-	if (!get_page_tag_ref(&new->page, &ref_new, &handle_new)) {
+	if (!get_page_tag_ref(folio_page(new, 0), &ref_new, &handle_new)) {
 		put_page_tag_ref(handle_old);
 		return;
 	}
diff --git a/mm/compaction.c b/mm/compaction.c
index f1b2060eb2016..d708d973250a4 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1845,7 +1845,6 @@ static void isolate_freepages(struct compact_control *cc)
 static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long data)
 {
 	struct compact_control *cc = (struct compact_control *)data;
-	struct folio *dst;
 	int order = folio_order(src);
 	bool has_isolated_pages = false;
 	int start_order;
@@ -1878,15 +1877,13 @@ static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long da
 
 		list_add(&freepage[size].lru, &cc->freepages[start_order]);
 	}
-	dst = (struct folio *)freepage;
-
-	post_alloc_hook(&dst->page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
-	set_page_refcounted(&dst->page);
+	post_alloc_hook(freepage, order, __GFP_MOVABLE, ALLOC_DEFAULT);
+	set_page_refcounted(freepage);
 	if (order)
-		prep_compound_page(&dst->page, order);
+		prep_compound_page(freepage, order);
 	cc->nr_freepages -= 1 << order;
 	cc->nr_migratepages -= 1 << order;
-	return page_rmappable_folio(&dst->page);
+	return page_rmappable_folio(freepage);
 }
 
 static struct folio *compaction_alloc(struct folio *src, unsigned long data)
@@ -1903,10 +1900,10 @@ static void compaction_free(struct folio *dst, unsigned long data)
 {
 	struct compact_control *cc = (struct compact_control *)data;
 	int order = folio_order(dst);
-	struct page *page = &dst->page;
+	struct page *page = folio_page(dst, 0);
 
 	if (folio_put_testzero(dst) && free_pages_prepare(page, order)) {
-		list_add(&dst->lru, &cc->freepages[order]);
+		list_add(&page->lru, &cc->freepages[order]);
 		cc->nr_freepages += 1 << order;
 	}
 	cc->nr_migratepages += 1 << order;
diff --git a/mm/filemap.c b/mm/filemap.c
index b74bc1e5015c6..02e0c2af594ca 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -156,7 +156,7 @@ static void filemap_unaccount_folio(struct address_space *mapping,
 	if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(folio_mapped(folio))) {
 		pr_alert("BUG: Bad page cache in process %s  pfn:%05lx\n",
 			 current->comm, folio_pfn(folio));
-		dump_page(&folio->page, "still mapped when deleted");
+		dump_page(folio_page(folio, 0), "still mapped when deleted");
 		dump_stack();
 		add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 
@@ -3888,7 +3888,7 @@ static vm_fault_t filemap_map_order0_folio(struct vm_fault *vmf,
 		unsigned long *rss)
 {
 	vm_fault_t ret = 0;
-	struct page *page = &folio->page;
+	struct page *page = folio_page(folio, 0);
 
 	if (PageHWPoison(page))
 		goto out;
@@ -4239,7 +4239,7 @@ static struct page *do_read_cache_page(struct address_space *mapping,
 
 	folio = do_read_cache_folio(mapping, index, filler, file, gfp);
 	if (IS_ERR(folio))
-		return &folio->page;
+		return ERR_CAST(folio);
 	return folio_file_page(folio, index);
 }
 
diff --git a/mm/folio.c b/mm/folio.c
index 35e242b48870b..978565add078e 100644
--- a/mm/folio.c
+++ b/mm/folio.c
@@ -103,7 +103,7 @@ void __folio_put(struct folio *folio)
 	page_cache_release(folio);
 	folio_unqueue_deferred_split(folio);
 	mem_cgroup_uncharge(folio);
-	free_frozen_pages(&folio->page, folio_order(folio));
+	free_frozen_pages(folio_page(folio, 0), folio_order(folio));
 }
 EXPORT_SYMBOL(__folio_put);
 
diff --git a/mm/gup.c b/mm/gup.c
index 8e9ef5ee7498c..1ce7ea5e7abb5 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -59,10 +59,11 @@ static inline void sanity_check_pinned_pages(struct page **pages,
 		    !folio_test_anon(folio))
 			continue;
 		if (!folio_test_large(folio) || folio_test_hugetlb(folio))
-			VM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(&folio->page), folio);
+			VM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(folio_page(folio, 0)),
+					      folio);
 		else
 			/* Either a PTE-mapped or a PMD-mapped THP. */
-			VM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(&folio->page) &&
+			VM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(folio_page(folio, 0)) &&
 					     !PageAnonExclusive(page), page);
 	}
 }
@@ -2957,7 +2958,8 @@ static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp,
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
-	if (!pmd_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) {
+	if (!pmd_write(orig) &&
+	    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
@@ -2999,7 +3001,8 @@ static unsigned long gup_fast_pud_leaf(pud_t orig, pud_t *pudp,
 		return 0;
 	}
 
-	if (!pud_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) {
+	if (!pud_write(orig) &&
+	    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
diff --git a/mm/gup_test.c b/mm/gup_test.c
index ba74bf3f41048..337b58221c792 100644
--- a/mm/gup_test.c
+++ b/mm/gup_test.c
@@ -59,13 +59,15 @@ static void verify_dma_pinned(unsigned int cmd, struct page **pages,
 			if (WARN(!folio_maybe_dma_pinned(folio),
 				 "pages[%lu] is NOT dma-pinned\n", i)) {
 
-				dump_page(&folio->page, "gup_test failure");
+				dump_page(folio_page(folio, 0),
+					  "gup_test failure");
 				break;
 			} else if (cmd == PIN_LONGTERM_BENCHMARK &&
 				WARN(!folio_is_longterm_pinnable(folio),
 				     "pages[%lu] is NOT pinnable but pinned\n",
 				     i)) {
-				dump_page(&folio->page, "gup_test failure");
+				dump_page(folio_page(folio, 0),
+					  "gup_test failure");
 				break;
 			}
 		}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ddc631a388b93..58fbc4d4ddb8b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1664,7 +1664,8 @@ static vm_fault_t insert_pmd(struct vm_area_struct *vma, unsigned long addr,
 			entry = pmd_mkspecial(entry);
 		} else {
 			folio_get(fop.folio);
-			folio_add_file_rmap_pmd(fop.folio, &fop.folio->page, vma);
+			folio_add_file_rmap_pmd(fop.folio,
+						folio_page(fop.folio, 0), vma);
 			add_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PMD_NR);
 		}
 	} else {
@@ -1786,7 +1787,8 @@ static vm_fault_t insert_pud(struct vm_area_struct *vma, unsigned long addr,
 		entry = folio_mk_pud(fop.folio, vma->vm_page_prot);
 
 		folio_get(fop.folio);
-		folio_add_file_rmap_pud(fop.folio, &fop.folio->page, vma);
+		folio_add_file_rmap_pud(fop.folio,
+					folio_page(fop.folio, 0), vma);
 		add_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PUD_NR);
 	} else {
 		entry = pud_mkhuge(pfn_pud(fop.pfn, prot));
@@ -1935,7 +1937,7 @@ static void copy_huge_non_present_pmd(
 		 * folio_try_dup_anon_rmap_pmd does not fail for
 		 * device private entries.
 		 */
-		folio_try_dup_anon_rmap_pmd(src_folio, &src_folio->page,
+		folio_try_dup_anon_rmap_pmd(src_folio, folio_page(src_folio, 0),
 					    dst_vma, src_vma);
 	}
 
@@ -2487,7 +2489,7 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 
 	/* Present and device private folios are rmappable. */
 	if (is_present || is_device_private)
-		folio_remove_rmap_pmd(folio, &folio->page, vma);
+		folio_remove_rmap_pmd(folio, folio_page(folio, 0), vma);
 
 	if (folio_test_anon(folio)) {
 		add_mm_counter(mm, MM_ANONPAGES, -HPAGE_PMD_NR);
@@ -2572,7 +2574,7 @@ bool zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
 
 	spin_unlock(ptl);
 	if (is_present && folio)
-		tlb_remove_page_size(tlb, &folio->page, HPAGE_PMD_SIZE);
+		tlb_remove_page_size(tlb, folio_page(folio, 0), HPAGE_PMD_SIZE);
 	return true;
 }
 
@@ -2947,7 +2949,7 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
 	}
 	if (src_folio) {
 		if (folio_maybe_dma_pinned(src_folio) ||
-		    !PageAnonExclusive(&src_folio->page)) {
+		    !PageAnonExclusive(folio_page(src_folio, 0))) {
 			err = -EBUSY;
 			goto unlock_ptls;
 		}
@@ -3709,7 +3711,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
 	 * the flags from the original folio.
 	 */
 	for (i = new_nr_pages; i < nr_pages; i += new_nr_pages) {
-		struct page *new_head = &folio->page + i;
+		struct page *new_head = folio_page(folio, i);
 		/*
 		 * Careful: new_folio is not a "real" folio before we cleared PageTail.
 		 * Don't pass it around before clear_compound_head().
@@ -3806,7 +3808,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
 	if (new_order)
 		folio_set_order(folio, new_order);
 	else
-		ClearPageCompound(&folio->page);
+		ClearPageCompound(folio_page(folio, 0));
 }
 
 /**
@@ -3896,7 +3898,7 @@ static int __split_frozen_folio(struct folio *folio, int new_order,
 		}
 
 		folio_split_memcg_refs(folio, old_order, split_order);
-		split_page_owner(&folio->page, old_order, split_order);
+		split_page_owner(folio_page(folio, 0), old_order, split_order);
 		pgalloc_tag_split(folio, old_order, split_order);
 		__split_folio_to_order(folio, old_order, split_order);
 
@@ -4392,7 +4394,7 @@ int folio_split_unmapped(struct folio *folio, unsigned int new_order)
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_large(folio), folio);
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_anon(folio), folio);
 
-	return __folio_freeze_split_anon(folio, new_order, &folio->page,
+	return __folio_freeze_split_anon(folio, new_order, folio_page(folio, 0),
 					 false, NULL, SPLIT_TYPE_UNIFORM);
 }
 
@@ -4448,7 +4450,7 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list
 {
 	struct folio *folio = page_folio(page);
 
-	return __folio_split(folio, new_order, &folio->page, page, list,
+	return __folio_split(folio, new_order, folio_page(folio, 0), page, list,
 			     SPLIT_TYPE_UNIFORM);
 }
 
@@ -4479,8 +4481,8 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list
 int folio_split(struct folio *folio, unsigned int new_order,
 		struct page *split_at, struct list_head *list)
 {
-	return __folio_split(folio, new_order, split_at, &folio->page, list,
-			     SPLIT_TYPE_NON_UNIFORM);
+	return __folio_split(folio, new_order, split_at, folio_page(folio, 0),
+			     list, SPLIT_TYPE_NON_UNIFORM);
 }
 
 /**
@@ -4512,7 +4514,7 @@ unsigned int min_order_for_split(struct folio *folio)
 
 int split_folio_to_list(struct folio *folio, struct list_head *list)
 {
-	return split_huge_page_to_list_to_order(&folio->page, list, 0);
+	return split_huge_page_to_list_to_order(folio_page(folio, 0), list, 0);
 }
 
 /*
@@ -5186,12 +5188,13 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct folio *folio
 		if (!softleaf_is_migration_read(entry))
 			rmap_flags |= RMAP_EXCLUSIVE;
 
-		folio_add_anon_rmap_pmd(folio, &folio->page, vma, haddr, rmap_flags);
+		folio_add_anon_rmap_pmd(folio, folio_page(folio, 0), vma,
+					haddr, rmap_flags);
 	} else {
-		folio_add_file_rmap_pmd(folio, &folio->page, vma);
+		folio_add_file_rmap_pmd(folio, folio_page(folio, 0), vma);
 	}
 	VM_WARN_ON_ONCE(pmd_write(pmde) && folio_test_anon(folio) &&
-			!PageAnonExclusive(&folio->page));
+			!PageAnonExclusive(folio_page(folio, 0)));
 	set_pmd_at(mm, haddr, pvmw->pmd, pmde);
 
 	/* No need to invalidate - it was non-present before */
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a1b51251103b3..31ca8777ccbac 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1274,7 +1274,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,
 		if (folio_test_hwpoison(folio))
 			continue;
 
-		if (is_migrate_isolate_page(&folio->page))
+		if (is_migrate_isolate_page(folio_page(folio, 0)))
 			continue;
 
 		list_move(&folio->lru, &h->hugepage_activelist);
@@ -1511,7 +1511,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
 	if (folio_test_hugetlb_cma(folio))
 		hugetlb_cma_free_frozen_folio(folio);
 	else
-		free_frozen_pages(&folio->page, folio_order(folio));
+		free_frozen_pages(folio_page(folio, 0), folio_order(folio));
 }
 
 /*
@@ -1701,7 +1701,7 @@ void free_huge_folio(struct folio *folio)
 
 	hugetlb_set_folio_subpool(folio, NULL);
 	if (folio_test_anon(folio))
-		__ClearPageAnonExclusive(&folio->page);
+		__ClearPageAnonExclusive(folio_page(folio, 0));
 	folio->mapping = NULL;
 	restore_reserve = folio_test_hugetlb_restore_reserve(folio);
 	folio_clear_hugetlb_restore_reserve(folio);
@@ -3238,7 +3238,7 @@ static void __init hugetlb_folio_init_tail_vmemmap(struct folio *folio,
 	 */
 	for (pfn = head_pfn + start_page_number; pfn < end_pfn; page++, pfn++) {
 		__init_single_page(page, pfn, zone, nid);
-		prep_compound_tail(page, &folio->page, order);
+		prep_compound_tail(page, folio_page(folio, 0), order);
 		set_page_count(page, 0);
 	}
 }
@@ -3259,7 +3259,7 @@ static void __init hugetlb_folio_init_vmemmap(struct folio *folio,
 	ret = folio_ref_freeze(folio, 1);
 	VM_BUG_ON(!ret);
 	hugetlb_folio_init_tail_vmemmap(folio, h, 1, nr_pages);
-	prep_compound_head(&folio->page, huge_page_order(h));
+	prep_compound_head(folio_page(folio, 0), huge_page_order(h));
 }
 
 /*
@@ -4004,7 +4004,8 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,
 
 		list_del(&folio->lru);
 
-		split_page_owner(&folio->page, huge_page_order(src), huge_page_order(dst));
+		split_page_owner(folio_page(folio, 0), huge_page_order(src),
+				 huge_page_order(dst));
 		pgalloc_tag_split(folio, huge_page_order(src), huge_page_order(dst));
 
 		for (i = 0; i < pages_per_huge_page(src); i += pages_per_huge_page(dst)) {
@@ -5605,9 +5606,9 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)
 	 * be leaks between processes, for example, with FOLL_GET users.
 	 */
 	if (folio_mapcount(old_folio) == 1 && folio_test_anon(old_folio)) {
-		if (!PageAnonExclusive(&old_folio->page)) {
+		if (!PageAnonExclusive(folio_page(old_folio, 0))) {
 			folio_move_anon_rmap(old_folio, vma);
-			SetPageAnonExclusive(&old_folio->page);
+			SetPageAnonExclusive(folio_page(old_folio, 0));
 		}
 		if (likely(!unshare))
 			set_huge_ptep_maybe_writable(vma, vmf->address,
@@ -5616,8 +5617,8 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)
 		delayacct_wpcopy_end();
 		return 0;
 	}
-	VM_BUG_ON_PAGE(folio_test_anon(old_folio) &&
-		       PageAnonExclusive(&old_folio->page), &old_folio->page);
+	VM_BUG_ON_FOLIO(folio_test_anon(old_folio) &&
+			PageAnonExclusive(folio_page(old_folio, 0)), old_folio);
 
 	/*
 	 * If the process that created a MAP_PRIVATE mapping is about to perform
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index 95fd2d190f0d2..e0fdd07cc6a99 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -47,7 +47,8 @@ static phys_addr_t __init memblock_node_memory_size(int nid)
 void hugetlb_cma_free_frozen_folio(struct folio *folio)
 {
 	WARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],
-					 &folio->page, folio_nr_pages(folio)));
+					 folio_page(folio, 0),
+					 folio_nr_pages(folio)));
 }
 
 struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index 0057fa2a16a89..807c6bb23997e 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -403,7 +403,7 @@ static int __hugetlb_vmemmap_restore_folio(const struct hstate *h,
 	if (!folio_test_hugetlb_vmemmap_optimized(folio))
 		return 0;
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	vmemmap_start	+= HUGETLB_VMEMMAP_RESERVE_SIZE;
@@ -531,11 +531,11 @@ static int __hugetlb_vmemmap_optimize_folio(const struct hstate *h,
 		goto out;
 	}
 
-	copy_page(page_to_virt(vmemmap_head), folio);
+	copy_page(page_to_virt(vmemmap_head), folio_page(folio, 0));
 	list_add(&vmemmap_head->lru, vmemmap_pages);
 	memmap_pages_add(1);
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	/*
@@ -578,7 +578,7 @@ static int hugetlb_vmemmap_split_folio(const struct hstate *h, struct folio *fol
 	if (!vmemmap_should_optimize_folio(h, folio))
 		return 0;
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	/*
@@ -610,7 +610,7 @@ static void __hugetlb_vmemmap_optimize_folios(struct hstate *h,
 			 * Already optimized by pre-HVO, just map the
 			 * mirrored tail page structs RO.
 			 */
-			spfn = (unsigned long)&folio->page;
+			spfn = (unsigned long)folio_page(folio, 0);
 			epfn = spfn + hugetlb_vmemmap_size(h);
 			vmemmap_wrprotect_hvo(spfn, epfn, folio_nid(folio),
 					HUGETLB_VMEMMAP_RESERVE_SIZE);
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index a11222572f978..127e5d75aa0d5 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -131,7 +131,7 @@ static int hwpoison_inject(void *data, u64 val)
 	 * the targeted owner (or on a free page).
 	 * memory_failure() will redo the check reliably inside page lock.
 	 */
-	err = hwpoison_filter(&folio->page);
+	err = hwpoison_filter(folio_page(folio, 0));
 	if (err)
 		return 0;
 
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 913086eaf17ba..63acb13f24ebd 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1793,7 +1793,7 @@ static void collect_mm_slot(struct mm_slot *slot)
 
 /* folio must be locked, and mmap_lock must be held */
 static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long addr,
-		pmd_t *pmdp, struct folio *folio, struct page *page)
+		pmd_t *pmdp, struct folio *folio)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	struct vm_fault vmf = {
@@ -1821,7 +1821,7 @@ static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long a
 	}
 
 	vmf.pmd = pmdp;
-	if (do_set_pmd(&vmf, folio, page))
+	if (do_set_pmd(&vmf, folio, folio_page(folio, 0)))
 		return SCAN_FAIL;
 
 	folio_get(folio);
@@ -2032,7 +2032,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 maybe_install_pmd:
 	/* step 5: install pmd entry */
 	result = install_pmd
-			? set_huge_pmd(vma, haddr, pmd, folio, &folio->page)
+			? set_huge_pmd(vma, haddr, pmd, folio)
 			: SCAN_SUCCEED;
 	goto drop_folio;
 abort:
diff --git a/mm/ksm.c b/mm/ksm.c
index f33523a84a1a1..bb8c564d9ffb5 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1112,7 +1112,8 @@ struct ksm_stable_node *folio_stable_node(const struct folio *folio)
 static inline void folio_set_stable_node(struct folio *folio,
 					 struct ksm_stable_node *stable_node)
 {
-	VM_WARN_ON_FOLIO(folio_test_anon(folio) && PageAnonExclusive(&folio->page), folio);
+	VM_WARN_ON_FOLIO(folio_test_anon(folio) &&
+			 PageAnonExclusive(folio_page(folio, 0)), folio);
 	WRITE_ONCE(folio->mapping,
 		   (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM));
 }
@@ -1324,7 +1325,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
 	if (unlikely(!pte_present(entry)))
 		goto out_unlock;
 
-	anon_exclusive = PageAnonExclusive(&folio->page);
+	anon_exclusive = PageAnonExclusive(folio_page(folio, 0));
 	if (pte_write(entry) || pte_dirty(entry) ||
 	    anon_exclusive || mm_tlb_flush_pending(mm)) {
 		swapped = folio_test_swapcache(folio);
@@ -1355,7 +1356,8 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
 
 		/* See folio_try_share_anon_rmap_pte(): clear PTE first. */
 		if (anon_exclusive &&
-		    folio_try_share_anon_rmap_pte(folio, &folio->page)) {
+		    folio_try_share_anon_rmap_pte(folio,
+						  folio_page(folio, 0))) {
 			set_pte_at(mm, pvmw.address, pvmw.pte, entry);
 			goto out_unlock;
 		}
@@ -1893,7 +1895,7 @@ static struct folio *stable_tree_search(struct page *page)
 			goto again;
 		}
 
-		ret = memcmp_pages(page, &tree_folio->page);
+		ret = memcmp_pages(page, folio_page(tree_folio, 0));
 		folio_put(tree_folio);
 
 		parent = *new;
@@ -2100,7 +2102,8 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
 			goto again;
 		}
 
-		ret = memcmp_pages(&kfolio->page, &tree_folio->page);
+		ret = memcmp_pages(folio_page(kfolio, 0),
+				   folio_page(tree_folio, 0));
 		folio_put(tree_folio);
 
 		parent = *new;
@@ -2333,7 +2336,8 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
 		if (kfolio == ERR_PTR(-EBUSY))
 			return;
 
-		err = try_to_merge_with_ksm_page(rmap_item, page, &kfolio->page);
+		err = try_to_merge_with_ksm_page(rmap_item, page,
+						 folio_page(kfolio, 0));
 		if (!err) {
 			/*
 			 * The page was successfully merged:
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 0c96eb5119976..771a75eb55050 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1400,7 +1400,7 @@ static int __get_hwpoison_page(struct page *page, unsigned long flags)
 	 * unsupported type of folio in order to reduce the risk of unexpected
 	 * races caused by taking a folio refcount.
 	 */
-	if (!HWPoisonHandlable(&folio->page, flags))
+	if (!HWPoisonHandlable(folio_page(folio, 0), flags))
 		return -EBUSY;
 
 	if (folio_try_get(folio)) {
@@ -1777,7 +1777,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	if (!cookie)
 		return -EBUSY;
 
-	if (hwpoison_filter(&folio->page)) {
+	if (hwpoison_filter(folio_page(folio, 0))) {
 		rc = -EOPNOTSUPP;
 		goto unlock;
 	}
@@ -1799,7 +1799,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	 * Use this flag as an indication that the dax page has been
 	 * remapped UC to prevent speculative consumption of poison.
 	 */
-	SetPageHWPoison(&folio->page);
+	folio_set_hwpoison(folio);
 
 	/*
 	 * Unlike System-RAM there is no possibility to swap in a
@@ -1808,7 +1808,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	 * SIGBUS (i.e. MF_MUST_KILL)
 	 */
 	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
-	collect_procs(folio, &folio->page, &to_kill, true);
+	collect_procs(folio, folio_page(folio, 0), &to_kill, true);
 
 	unmap_and_kill(&to_kill, pfn, folio->mapping, folio->index, flags);
 unlock:
diff --git a/mm/memory.c b/mm/memory.c
index 1f83a26f87333..e7c86e7301923 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1098,7 +1098,8 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
 	 * over and copy the page & arm it.
 	 */
 
-	if (copy_mc_user_highpage(&new_folio->page, page, addr, src_vma))
+	if (copy_mc_user_highpage(folio_page(new_folio, 0), page, addr,
+				  src_vma))
 		return -EHWPOISON;
 
 	*prealloc = NULL;
@@ -4035,7 +4036,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 	if (!pfn_is_zero) {
 		int err;
 
-		err = __wp_page_copy_user(&new_folio->page, vmf->page, vmf);
+		err = __wp_page_copy_user(folio_page(new_folio, 0), vmf->page,
+					  vmf);
 		if (err) {
 			/*
 			 * COW failed, if the fault was solved by other,
@@ -4051,7 +4053,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 			delayacct_wpcopy_end();
 			return err == -EHWPOISON ? VM_FAULT_HWPOISON : 0;
 		}
-		kmsan_copy_page_meta(&new_folio->page, vmf->page);
+		kmsan_copy_page_meta(folio_page(new_folio, 0), vmf->page);
 	}
 
 	__folio_mark_uptodate(new_folio);
@@ -5105,7 +5107,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
 		ptep = folio_ptep;
 		nr_pages = nr;
 		entry = folio->swap;
-		page = &folio->page;
+		page = folio_page(folio, 0);
 	}
 
 check_folio:
@@ -5659,7 +5661,7 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa
 
 	if (!is_pmd_order(folio_order(folio)))
 		return ret;
-	page = &folio->page;
+	page = folio_page(folio, 0);
 
 	/*
 	 * Just backoff if any subpage of a THP is corrupted otherwise
@@ -5870,7 +5872,7 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
 		} else {
 			/* Now we can set mappings for the whole large folio. */
 			addr = vmf->address - idx * PAGE_SIZE;
-			page = &folio->page;
+			page = folio_page(folio, 0);
 		}
 	}
 
@@ -6055,7 +6057,7 @@ static vm_fault_t do_cow_fault(struct vm_fault *vmf)
 	if (!folio)
 		return VM_FAULT_OOM;
 
-	vmf->cow_page = &folio->page;
+	vmf->cow_page = folio_page(folio, 0);
 
 	ret = __do_fault(vmf);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 796af1028ee23..47bf3b5d3ff27 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1952,7 +1952,7 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 				if (__ratelimit(&migrate_rs)) {
 					pr_warn("migrating pfn %lx failed ret:%d\n",
 						folio_pfn(folio), ret);
-					dump_page(&folio->page,
+					dump_page(folio_page(folio, 0),
 						  "migration failure");
 				}
 			}
diff --git a/mm/memremap.c b/mm/memremap.c
index accba23aef28c..70cfd3f05a257 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -467,7 +467,7 @@ void free_zone_device_folio(struct folio *folio)
 		break;
 
 	case MEMORY_DEVICE_FS_DAX:
-		wake_up_var(&folio->page);
+		wake_up_var(folio_page(folio, 0));
 		break;
 
 	case MEMORY_DEVICE_PCI_P2PDMA:
diff --git a/mm/migrate.c b/mm/migrate.c
index 7bdcdb57652f8..b027c938d8301 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -266,8 +266,8 @@ void putback_movable_pages(struct list_head *l)
 			continue;
 		}
 		list_del(&folio->lru);
-		if (unlikely(page_has_movable_ops(&folio->page))) {
-			putback_movable_ops_page(&folio->page);
+		if (unlikely(page_has_movable_ops(folio_page(folio, 0)))) {
+			putback_movable_ops_page(folio_page(folio, 0));
 		} else {
 			node_stat_mod_folio(folio, NR_ISOLATED_ANON +
 					folio_is_file_lru(folio), -folio_nr_pages(folio));
@@ -282,8 +282,8 @@ bool isolate_folio_to_list(struct folio *folio, struct list_head *list)
 	if (folio_test_hugetlb(folio))
 		return folio_isolate_hugetlb(folio, list);
 
-	if (page_has_movable_ops(&folio->page)) {
-		if (!isolate_movable_ops_page(&folio->page,
+	if (page_has_movable_ops(folio_page(folio, 0))) {
+		if (!isolate_movable_ops_page(folio_page(folio, 0),
 					      ISOLATE_UNEVICTABLE))
 			return false;
 	} else {
@@ -1199,7 +1199,8 @@ static void migrate_folio_undo_dst(struct folio *dst, bool locked,
 static void migrate_folio_done(struct folio *src,
 			       enum migrate_reason reason)
 {
-	if (likely(!page_has_movable_ops(&src->page)) && reason != MR_DEMOTION)
+	if (likely(!page_has_movable_ops(folio_page(src, 0))) &&
+	    reason != MR_DEMOTION)
 		mod_node_page_state(folio_pgdat(src), NR_ISOLATED_ANON +
 				    folio_is_file_lru(src), -folio_nr_pages(src));
 
@@ -1308,7 +1309,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
 		goto out;
 	dst_locked = true;
 
-	if (unlikely(page_has_movable_ops(&src->page))) {
+	if (unlikely(page_has_movable_ops(folio_page(src, 0)))) {
 		__migrate_folio_record(dst, old_folio_state, anon_vma);
 		return 0;
 	}
@@ -1375,8 +1376,9 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
 	prev = dst->lru.prev;
 	list_del(&dst->lru);
 
-	if (unlikely(page_has_movable_ops(&src->page))) {
-		rc = migrate_movable_ops_page(&dst->page, &src->page, mode);
+	if (unlikely(page_has_movable_ops(folio_page(src, 0)))) {
+		rc = migrate_movable_ops_page(folio_page(dst, 0),
+					      folio_page(src, 0), mode);
 		if (rc)
 			goto out;
 		goto out_unlock_both;
@@ -1903,7 +1905,7 @@ static int migrate_pages_batch(struct list_head *from,
 			 * If we are holding the last folio reference, the folio
 			 * was freed from under us, so just drop our reference.
 			 */
-			if (likely(!page_has_movable_ops(&folio->page)) &&
+			if (likely(!page_has_movable_ops(folio_page(folio, 0))) &&
 			    folio_ref_count(folio) == 1) {
 				folio_clear_active(folio);
 				folio_clear_unevictable(folio);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 641384085e341..870ff378d61d2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3006,17 +3006,18 @@ void free_unref_folios(struct folio_batch *folios)
 	/* Prepare folios for freeing */
 	for (i = 0, j = 0; i < folios->nr; i++) {
 		struct folio *folio = folios->folios[i];
+		struct page *page = folio_page(folio, 0);
 		unsigned long pfn = folio_pfn(folio);
 		unsigned int order = folio_order(folio);
 
-		if (!__free_pages_prepare(&folio->page, order, FPI_NONE))
+		if (!__free_pages_prepare(page, order, FPI_NONE))
 			continue;
 		/*
 		 * Free orders not handled on the PCP directly to the
 		 * allocator.
 		 */
 		if (!pcp_allowed_order(order)) {
-			free_one_page(folio_zone(folio), &folio->page,
+			free_one_page(folio_zone(folio), page,
 				      pfn, order, FPI_NONE);
 			continue;
 		}
@@ -3029,13 +3030,14 @@ void free_unref_folios(struct folio_batch *folios)
 
 	for (i = 0; i < folios->nr; i++) {
 		struct folio *folio = folios->folios[i];
+		struct page *page = folio_page(folio, 0);
 		struct zone *zone = folio_zone(folio);
 		unsigned long pfn = folio_pfn(folio);
 		unsigned int order = (unsigned long)folio->private;
 		int migratetype;
 
 		folio->private = NULL;
-		migratetype = get_pfnblock_migratetype(&folio->page, pfn);
+		migratetype = get_pfnblock_migratetype(page, pfn);
 
 		/* Different zone requires a different pcp lock */
 		if (zone != locked_zone ||
@@ -3051,7 +3053,7 @@ void free_unref_folios(struct folio_batch *folios)
 			 * allocator, see comment in free_frozen_pages.
 			 */
 			if (is_migrate_isolate(migratetype)) {
-				free_one_page(zone, &folio->page, pfn,
+				free_one_page(zone, page, pfn,
 					      order, FPI_NONE);
 				continue;
 			}
@@ -3062,7 +3064,7 @@ void free_unref_folios(struct folio_batch *folios)
 			 */
 			pcp = pcp_spin_trylock(zone->per_cpu_pageset);
 			if (unlikely(!pcp)) {
-				free_one_page(zone, &folio->page, pfn,
+				free_one_page(zone, page, pfn,
 					      order, FPI_NONE);
 				continue;
 			}
@@ -3076,9 +3078,9 @@ void free_unref_folios(struct folio_batch *folios)
 		if (unlikely(migratetype >= MIGRATE_PCPTYPES))
 			migratetype = MIGRATE_MOVABLE;
 
-		trace_mm_page_free_batched(&folio->page);
-		if (!free_frozen_page_commit(zone, pcp, &folio->page,
-				migratetype, order, FPI_NONE)) {
+		trace_mm_page_free_batched(page);
+		if (!free_frozen_page_commit(zone, pcp, page,
+					     migratetype, order, FPI_NONE)) {
 			pcp = NULL;
 			locked_zone = NULL;
 		}
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 5aaad037384e4..29c9e108b2e59 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -47,7 +47,7 @@ bool page_is_unmovable(struct zone *zone, struct page *page,
 		unsigned long nr_pages, pfn;
 		unsigned int order;
 
-		order = compound_order(&folio->page);
+		order = compound_order(folio_page(folio, 0));
 		if (order > MAX_FOLIO_ORDER)
 			return true;
 
diff --git a/mm/page_owner.c b/mm/page_owner.c
index cfc31c92d7657..39c381699a633 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -365,7 +365,7 @@ noinline void __set_page_owner(struct page *page, unsigned short order,
 
 void __folio_set_owner_migrate_reason(struct folio *folio, enum migrate_reason reason)
 {
-	struct page_ext *page_ext = page_ext_get(&folio->page);
+	struct page_ext *page_ext = page_ext_get(folio_page(folio, 0));
 	struct page_owner *page_owner;
 
 	if (unlikely(!page_ext))
@@ -398,14 +398,14 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	struct page_owner *new_page_owner;
 	depot_stack_handle_t migrate_handle;
 
-	page_ext = page_ext_get(&old->page);
+	page_ext = page_ext_get(folio_page(old, 0));
 	if (unlikely(!page_ext))
 		return;
 
 	old_page_owner = get_page_owner(page_ext);
 	page_ext_put(page_ext);
 
-	page_ext = page_ext_get(&newfolio->page);
+	page_ext = page_ext_get(folio_page(newfolio, 0));
 	if (unlikely(!page_ext))
 		return;
 
@@ -413,7 +413,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	page_ext_put(page_ext);
 
 	migrate_handle = new_page_owner->handle;
-	__update_page_owner_handle(&newfolio->page, old_page_owner->handle,
+	__update_page_owner_handle(folio_page(newfolio, 0),
+				   old_page_owner->handle,
 				   old_page_owner->order, old_page_owner->gfp_mask,
 				   old_page_owner->last_migrate_reason,
 				   old_page_owner->ts_nsec, old_page_owner->pid,
@@ -423,7 +424,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	 * will be freed after migration. Keep them until then as they may be
 	 * useful.
 	 */
-	__update_page_owner_free_handle(&newfolio->page, 0, old_page_owner->order,
+	__update_page_owner_free_handle(folio_page(newfolio, 0), 0,
+					old_page_owner->order,
 					old_page_owner->free_pid,
 					old_page_owner->free_tgid,
 					old_page_owner->free_ts_nsec);
@@ -433,7 +435,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	 * when subtracting those pages from the stack.
 	 */
 	rcu_read_lock();
-	for_each_page_ext(&old->page, 1 << new_page_owner->order, page_ext, iter) {
+	for_each_page_ext(folio_page(old, 0), 1 << new_page_owner->order,
+			  page_ext, iter) {
 		old_page_owner = get_page_owner(page_ext);
 		old_page_owner->handle = migrate_handle;
 	}
diff --git a/mm/rmap.c b/mm/rmap.c
index fbd66a2823b7b..cd1cf570c770d 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1668,7 +1668,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 		/* increment count (starts at -1) */
 		atomic_set(&folio->_mapcount, 0);
 		if (exclusive)
-			SetPageAnonExclusive(&folio->page);
+			SetPageAnonExclusive(folio_page(folio, 0));
 	} else if (!folio_test_pmd_mappable(folio)) {
 		int i;
 
@@ -1694,7 +1694,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 		if (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))
 			atomic_set(&folio->_nr_pages_mapped, ENTIRELY_MAPPED);
 		if (exclusive)
-			SetPageAnonExclusive(&folio->page);
+			SetPageAnonExclusive(folio_page(folio, 0));
 		nr_pmdmapped = nr;
 	}
 
@@ -3187,9 +3187,9 @@ void hugetlb_add_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 	atomic_inc(&folio->_entire_mapcount);
 	atomic_inc(&folio->_large_mapcount);
 	if (flags & RMAP_EXCLUSIVE)
-		SetPageAnonExclusive(&folio->page);
+		SetPageAnonExclusive(folio_page(folio, 0));
 	VM_WARN_ON_FOLIO(folio_entire_mapcount(folio) > 1 &&
-			 PageAnonExclusive(&folio->page), folio);
+			 PageAnonExclusive(folio_page(folio, 0)), folio);
 }
 
 void hugetlb_add_new_anon_rmap(struct folio *folio,
@@ -3203,6 +3203,6 @@ void hugetlb_add_new_anon_rmap(struct folio *folio,
 	atomic_set(&folio->_large_mapcount, 0);
 	folio_clear_hugetlb_restore_reserve(folio);
 	__folio_set_anon(folio, vma, address, true);
-	SetPageAnonExclusive(&folio->page);
+	SetPageAnonExclusive(folio_page(folio, 0));
 }
 #endif /* CONFIG_HUGETLB_PAGE */
diff --git a/mm/shmem.c b/mm/shmem.c
index ae08cff4500c3..940af0067ddf4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -6192,7 +6192,7 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
 	struct page *page;
 
 	if (IS_ERR(folio))
-		return &folio->page;
+		return ERR_CAST(folio);
 
 	page = folio_file_page(folio, index);
 	if (PageHWPoison(page)) {
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 3c7fd39deb137..a39d7d40a76b0 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -565,7 +565,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,
 				goto err_folio_put;
 		}
 	} else if (uffd_flags_mode_is(flags, MFILL_ATOMIC_ZEROPAGE)) {
-		clear_user_highpage(&folio->page, state->dst_addr);
+		clear_user_highpage(folio_page(folio, 0), state->dst_addr);
 	} else {
 		VM_WARN_ONCE(1, "Unknown UFFDIO operation, flags: %x", flags);
 	}
@@ -584,7 +584,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,
 	}
 
 	ret = mfill_atomic_install_pte(state->pmd, state->vma, dst_addr,
-				       &folio->page, flags);
+				       folio_page(folio, 0), flags);
 	if (ret)
 		goto err_filemap_remove;
 
@@ -1268,7 +1268,8 @@ static struct folio *check_ptes_for_batched_move(struct vm_area_struct *src_vma,
 	folio = vm_normal_folio(src_vma, src_addr, orig_src_pte);
 	if (!folio || !folio_trylock(folio))
 		return NULL;
-	if (!PageAnonExclusive(&folio->page) || folio_test_large(folio)) {
+	if (!PageAnonExclusive(folio_page(folio, 0)) ||
+	    folio_test_large(folio)) {
 		folio_unlock(folio);
 		return NULL;
 	}
@@ -1306,7 +1307,7 @@ static long move_present_ptes(struct mm_struct *mm,
 	}
 	if (folio_test_large(src_folio) ||
 	    folio_maybe_dma_pinned(src_folio) ||
-	    !PageAnonExclusive(&src_folio->page)) {
+	    !PageAnonExclusive(folio_page(src_folio, 0))) {
 		err = -EBUSY;
 		goto out;
 	}
@@ -1590,7 +1591,8 @@ static long move_pages_ptes(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd
 			}
 
 			folio = vm_normal_folio(src_vma, src_addr, orig_src_pte);
-			if (!folio || !PageAnonExclusive(&folio->page)) {
+			if (!folio ||
+			    !PageAnonExclusive(folio_page(folio, 0))) {
 				spin_unlock(src_ptl);
 				ret = -EBUSY;
 				goto out;
@@ -2072,7 +2074,7 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
 					struct folio *folio = pmd_folio(*src_pmd);
 
 					if (!is_huge_zero_folio(folio) &&
-					    !PageAnonExclusive(&folio->page)) {
+					    !PageAnonExclusive(folio_page(folio, 0))) {
 						spin_unlock(ptl);
 						err = -EBUSY;
 						break;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 91295070ca336..150ffeec3d478 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1709,7 +1709,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,
 
 	list_for_each_entry_safe(folio, next, folio_list, lru) {
 		/* TODO: these pages should not even appear in this list. */
-		if (page_has_movable_ops(&folio->page))
+		if (page_has_movable_ops(folio_page(folio, 0)))
 			continue;
 		if (!folio_test_hugetlb(folio) && folio_is_file_lru(folio) &&
 		    !folio_test_dirty(folio) && !folio_test_unevictable(folio)) {

3/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19128
							output: 18
							thoughts: 71
						

Thoughts:
Here's my analysis of the situation:

**Initial Assessment of the Linux Kernel HEAD Commit**

Okay, so I need to evaluate the implications of that patch series applied as the current HEAD commit in the Linux kernel repository. My instinct is to start methodically. I need context, and the first place I'll go is the `git log`. I want to immediately get my hands on the commit message associated with `e0b2f96dcac870e7cec69519979c25607faf5cb4`. The log will hopefully give me a high-level summary of what the patch set aims to achieve, the reasoning behind it, and maybe even point me to relevant discussions or documentation. Understanding the stated intent is key before I start digging into the code itself.



4/2 2026/09/30 22:01 tool grepper
0m Args:
{
  "Expression": "mm:.*folio"
}

Results:
{
  "Output": "Documentation/mm/memory-model.rst=160=The users of `ZONE_DEVICE` are:\n--\nDocumentation/mm/memory-model.rst-164-\nDocumentation/mm/memory-model.rst:165:* hmm: Extend `ZONE_DEVICE` with `-\u003epage_fault()` and `-\u003efolio_free()`\nDocumentation/mm/memory-model.rst-166-  event callbacks to allow a device-driver to coordinate memory management\n--\narch/s390/kernel/uv.c=346=EXPORT_SYMBOL(__make_folio_secure);\n--\narch/s390/kernel/uv.c-350- *\t\t\t       split the folio if it is large.\narch/s390/kernel/uv.c:351: * @mm:    the mm containing the folio to work on\narch/s390/kernel/uv.c-352- * @folio: the folio\n"
}

5/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19624
							output: 32
							thoughts: 72
						

Thoughts:
Here's my thought process, as it went:

**Examining Folio Structure and Commit Details**

Okay, so I need to understand what's happening with this `folio->page` reference. Since I can't use `git log` directly, the logical next step is to examine the commit details using either `read-file` or `grepper` – hopefully, I can trace back where this particular variable is being defined or modified. I'm thinking I'll start by inspecting the code where `folio` is defined.

But hold on a second! Before I dive into hunting down the specific lines, a crucial step: let me first confirm the *definition* of the `struct folio` itself. That foundational information is crucial. So, I need to check `include/linux/mm_types.h`. That's where I'll find the structure's blueprint and any relevant member variables, including, crucially, the `page` member that I'm interested in! This will provide the crucial context.



6/2 2026/09/30 22:01 tool grepper
0m Args:
{
  "Expression": "struct folio \\{",
  "PathPrefix": "include/linux/mm_types.h"
}

Results:
{
  "Output": "include/linux/mm_types.h=334=typedef unsigned short mm_id_t;\n--\ninclude/linux/mm_types.h-403- */\ninclude/linux/mm_types.h:404:struct folio {\ninclude/linux/mm_types.h-405-\t/* private: don't document the anon union */\n"
}

7/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 20043
							output: 37
							thoughts: 26
						

Thoughts:
Okay, let's dive into this. I'm going to take a look at the `include/linux/mm_types.h` file, specifically lines 400 through 450. I want to refresh my memory on the internal data structures used in the Linux kernel's memory management system. I know this section likely deals with some critical structures; could be page tables, virtual memory areas (VMAs), or perhaps some of the more esoteric descriptors. Given that it's in `mm_types.h`, I'm expecting this will define some key data structures; I am interested in how the kernel represents and manages virtual memory regions. I also want to see how these structures link together. Let's start with a thorough analysis of this specific section.



8/2 2026/09/30 22:01 tool read-file
0m Args:
{
  "File": "include/linux/mm_types.h",
  "FirstLine": 400,
  "LineCount": 60
}

Results:
{
  "Contents": " 400:\t * power-of-two.  It may be mapped into userspace at an address which is\n 401:\t * at an arbitrary page offset, but its kernel virtual address is aligned\n 402:\t * to its size.\n 403:\t */\n 404:\tstruct folio {\n 405:\t\t/* private: don't document the anon union */\n 406:\t\tunion {\n 407:\t\t\tstruct {\n 408:\t\t/* public: */\n 409:\t\t\t\tmemdesc_flags_t flags;\n 410:\t\t\t\tunion {\n 411:\t\t\t\t\tstruct list_head lru;\n 412:\t\t/* private: avoid cluttering the output */\n 413:\t\t\t\t\t/* For the Unevictable \"LRU list\" slot */\n 414:\t\t\t\t\tstruct {\n 415:\t\t\t\t\t\t/* Avoid compound_info */\n 416:\t\t\t\t\t\tvoid *__filler;\n 417:\t\t/* public: */\n 418:\t\t\t\t\t\tunsigned int mlock_count;\n 419:\t\t/* private: */\n 420:\t\t\t\t\t};\n 421:\t\t/* public: */\n 422:\t\t\t\t\tstruct dev_pagemap *pgmap;\n 423:\t\t\t\t};\n 424:\t\t\t\tstruct address_space *mapping;\n 425:\t\t\t\tunion {\n 426:\t\t\t\t\tpgoff_t index;\n 427:\t\t\t\t\tunsigned long share;\n 428:\t\t\t\t};\n 429:\t\t\t\tunion {\n 430:\t\t\t\t\tvoid *private;\n 431:\t\t\t\t\tswp_entry_t swap;\n 432:\t\t\t\t\tunsigned long migrate_info;\n 433:\t\t\t\t};\n 434:\t\t\t\tatomic_t _mapcount;\n 435:\t\t\t\tatomic_t _refcount;\n 436:\t#ifdef CONFIG_MEMCG\n 437:\t\t\t\tunsigned long memcg_data;\n 438:\t#elif defined(CONFIG_SLAB_OBJ_EXT)\n 439:\t\t\t\tunsigned long _unused_slab_obj_exts;\n 440:\t#endif\n 441:\t#if defined(WANT_PAGE_VIRTUAL)\n 442:\t\t\t\tvoid *virtual;\n 443:\t#endif\n 444:\t#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS\n 445:\t\t\t\tint _last_cpupid;\n 446:\t#endif\n 447:\t\t/* private: the union with struct page is transitional */\n 448:\t\t\t};\n 449:\t\t\tstruct page page;\n 450:\t\t};\n 451:\t\tunion {\n 452:\t\t\tstruct {\n 453:\t\t\t\tunsigned long _flags_1;\n 454:\t\t\t\tunsigned long _head_1;\n 455:\t\t\t\tunion {\n 456:\t\t\t\t\tstruct {\n 457:\t\t/* public: */\n 458:\t\t\t\t\t\tatomic_t _large_mapcount;\n 459:\t\t\t\t\t\tatomic_t _nr_pages_mapped;\n"
}

9/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 21047
							output: 28
							thoughts: 757
						

Thoughts:
**Analyzing the Patch: Folio and Page Conversion**

Okay, let's dive into this patch. My immediate reaction is to meticulously examine the changes. It looks like we're transitioning from direct page manipulation to using `folio` structures and `folio_page()` more consistently. I see several instances of this pattern:

*   In `mm/alloc_tag.c`, we're changing `&folio->page` to `folio_page(folio, 0)`. Makes sense; we're now getting the underlying `struct page` from the folio object using the designated accessor, which is the correct way to handle this.
*   Similar changes are present in `mm/compaction.c`, `mm/filemap.c`, `mm/folio.c`, `mm/memory-failure.c` and elsewhere, consistently shifting away from direct `page` member access within folios. This suggests a broader refactoring effort.
*   I also noticed a change related to error handling in `mm/filemap.c` and `mm/shmem.c`: instead of returning `&folio->page` when `IS_ERR(folio)`, we're now returning `ERR_CAST(folio)`. Hold on...

That's when I had a moment of clarity. Let's look closely at `do_read_cache_page` in `mm/filemap.c`. Previously, we had `return &folio->page;` when `IS_ERR(folio)`. But now it returns `ERR_CAST(folio)`. *That* was the key! We were *inadvertently* returning the address of the `page` member within an error pointer, which is a disaster. It was returning `(struct page *)((void *)folio + offset)` instead of the error pointer `folio`.

Now, with the addition of `ERR_CAST(folio)`, this patch *correctly* returns the error pointer itself when `folio` represents an error condition. This is exactly what the code should have been doing. Looks like the same mistake was repeated in `mm/shmem.c`. Good catch! We are making the error handling consistent with the correct pattern in this area, and now the code is now returning the correct error pointer.

This is all about ensuring we handle `folio` objects and potential error conditions properly, especially in contexts where we need to retrieve the underlying `struct page`. The `folio_page()` function is the correct way to do it. It looks like this patch is eliminating a subtle but critical bug related to incorrect error handling.



10/2 2026/09/30 22:01 tool grepper
0m Args:
{
  "Expression": "#define folio_page|static inline struct page \\*folio_page"
}

Results:
{
  "Output": "include/linux/page-flags.h=277=static __always_inline void clear_compound_head(struct page *page)\n--\ninclude/linux/page-flags.h-307- */\ninclude/linux/page-flags.h:308:#define folio_page(folio, n)\t(\u0026(folio)-\u003epage + (n))\ninclude/linux/page-flags.h-309-\n"
}

11/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 22485
							output: 30
							thoughts: 2324
						

Thoughts:
**Fuzzing Decision for Folio/Page Abstraction Changes**

Alright, let's break this down. My initial assessment is that this patch *definitely* warrants fuzzing. `folio_page(folio, 0)` is the new way to get a `struct page*` from a `struct folio*` - replacing direct access via `&folio->page`. This isn't just a cosmetic change; it's a refactoring driven by Matthew Wilcox's effort to abstract the `struct page` away from the `struct folio`. The comments in `mm_types.h` confirm this: `/* private: the union with struct page is transitional */`. Eventually, `folio->page` will likely be gone or redefined.

Looking at the code, it's clear this touches *a lot* of core memory management code across `mm/compaction.c`, `mm/filemap.c`, `mm/huge_memory.c`, `mm/shmem.c`, and so on. The patch makes the following, non-exhaustive, changes that point to the need for fuzzing:

*   Replaces direct `struct page` access with `folio_page()` (e.g. `compaction_free`, `compaction_alloc_noprof`).
*   Replaces return of `&folio->page` with `ERR_CAST(folio)` (e.g. `mm/filemap.c`).
*   Alters assertions that reference `struct page` (e.g. `VM_BUG_ON_FOLIO`).
*   Changes function signatures (e.g. `set_huge_pmd` in `mm/khugepaged.c`).
*   Alters other `struct page` access methods like `__split_folio_to_order` and `folio_split`.

Based on the fuzzing guidelines, this hits multiple positive criteria: it touches reachable executable code in core memory management subsystems, refactors data structures (the folio/page relationship), and modifies runtime assertions.  Therefore, `WorthFuzzing = true`.

Now, we need to identify *FocusSymbols* – the functions we should target.  The goal is to avoid general, ubiquitous functions (memory allocators, page fault handlers, locks) and instead focus on code that specifically implements the new abstraction logic or provides entry points to the features under change.

Let's carefully examine the touched files:

1.  `mm/alloc_tag.c`:  The functions `pgalloc_tag_split(struct folio *folio, int old_order, int new_order)` and `pgalloc_tag_swap(struct folio *new, struct folio *old)` seem specific to the folio allocation tag feature and its interaction with the abstraction. They seem like good candidates.

2.  `mm/compaction.c`: The static functions `compaction_alloc_noprof`, `compaction_alloc`, and `compaction_free` are modified, but they are all static. They should be called from somewhere. So, we'll need to understand where these functions are used, and identify the non-static *entrypoints* or *callers* of these compaction functions. The compaction routines themselves could be considered a "feature" as well.  Further investigation into callers is required.

I need to go deeper into *how* these functions are used and *where* these new abstractions are used within this mm code base, and what the entrypoints are, to make the best decision for focusing fuzzing effort.



12/2 2026/09/30 22:01 tool grepper
0m Args:
{
  "Expression": "compaction_alloc",
  "PathPrefix": "mm/compaction.c"
}

Results:
{
  "Output": "mm/compaction.c=1725=static void isolate_freepages(struct compact_control *cc)\n--\nmm/compaction.c-1844- */\nmm/compaction.c:1845:static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long data)\nmm/compaction.c-1846-{\n--\nmm/compaction.c-1888-\nmm/compaction.c:1889:static struct folio *compaction_alloc(struct folio *src, unsigned long data)\nmm/compaction.c-1890-{\nmm/compaction.c:1891:\treturn alloc_hooks(compaction_alloc_noprof(src, data));\nmm/compaction.c-1892-}\n--\nmm/compaction.c=2559=compact_zone(struct compact_control *cc, struct capture_control *capc)\n--\nmm/compaction.c-2690-\t\t * Record the number of pages to migrate since the\nmm/compaction.c:2691:\t\t * compaction_alloc/free() will update cc-\u003enr_migratepages\nmm/compaction.c-2692-\t\t * properly.\n--\nmm/compaction.c-2694-\t\tnr_migratepages = cc-\u003enr_migratepages;\nmm/compaction.c:2695:\t\terr = migrate_pages(\u0026cc-\u003emigratepages, compaction_alloc,\nmm/compaction.c-2696-\t\t\t\tcompaction_free, (unsigned long)cc, cc-\u003emode,\n"
}

13/2 2026/09/30 22:01 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 25991
							output: 27
							thoughts: 1479
						

Thoughts:
**Analyzing Potential Performance Bottlenecks in the Kernel Memory Management Subsystem**

Alright, let's dive into this kernel code and see what stands out in terms of potential hot-paths and performance considerations. First up, in `compaction.c`, I notice the `compact_zone`, and the allocation/free functions. However, the use of `compaction_free` as a function pointer passed to `migrate_pages` immediately signals that they can't be inlined. This is important since inlining is a key optimization.

Next, I'm looking at `mm/filemap.c`. The `filemap_unaccount_folio`, `filemap_map_order0_folio` and `do_read_cache_page` functions are static, which may have limited reach. However, `do_read_cache_page` calls `read_mapping_page`, which is used ubiquitously, and should be considered a candidate for optimization. Page faults and filemap reads are frequent operations, so any improvements here would be beneficial.

Moving on to `mm/folio.c`, I see `__folio_put`, which is a fundamental lifecycle function. I need to keep that in mind. **Do NOT list `__folio_put`**. It's crucial, but it's part of the fabric of the kernel, not a bottleneck to be addressed.

In `mm/gup.c`, a few static functions jump out. In `mm/gup_test.c`, I see a static function as well, but it's in a test module - ioctl entrypoint `gup_test`.

Now, let's move into `mm/huge_memory.c`. I see a handful of functions here. Specifically, `split_folio_to_list`, `folio_split`, `folio_split_unmapped`, `move_pages_huge_pmd` and `zap_huge_pmd` look interesting. These are definitely related to THP and folio splitting. These are more specialized operations, so they are **not** as ubiquitous.

Moving to `mm/hugetlb.c`. There are a lot of `hugetlb` functions: `dequeue_hugetlb_folio_node_exact`, `__update_and_free_hugetlb_folio`, `free_huge_folio`... these are clearly part of huge page management, and I need to keep an eye on them.

In `mm/khugepaged.c`, `set_huge_pmd` and `try_collapse_pte_mapped_thp` are related to the automatic creation of THP, which is also not ubiquitous.

`mm/ksm.c` deals with Kernel Samepage Merging. This is a very targeted functionality and will not be ubiquitous.

`mm/memory-failure.c` handles memory errors with `__get_hwpoison_page` and similar functions.

Then I get into `mm/migrate.c`, which has a batch of functions: `putback_movable_pages`, `isolate_folio_to_list`, `migrate_folio_undo_dst`, `migrate_folio_done`, `migrate_folio_unmap`, `migrate_folio_move`, `migrate_pages_batch`. These are specific to page migration.

Moving onto `mm/userfaultfd.c`. This is for the User Fault mechanism. `move_pages` in `userfaultfd.c` is for `UFFDIO_MOVE` operation.

`shmem.c` has `shmem_read_mapping_page_gfp`.

Now, `mm/page_alloc.c` has `free_unref_folios` (generic deallocator) that should be ignored as part of lifecycle. **Do NOT list it**.

`mm/page_isolation.c` has `page_is_unmovable`.

`mm/page_owner.c` has `__folio_set_owner_migrate_reason` and `__folio_copy_owner`.

`mm/rmap.c` deals with reference counting: `folio_add_new_anon_rmap`, `hugetlb_add_anon_rmap` and `hugetlb_add_new_anon_rmap`.

`mm/memremap.c` has `free_zone_device_folio`.

`mm/vmscan.c` has `reclaim_clean_pages_from_list`.

Finally, to get a better understanding of the code, I need to look into CONFIG options and dependencies for the code that was touched. Where is `pgalloc_tag_split` defined, and what config guards `mm/alloc_tag.c`? That should give me a more complete picture.



14/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "alloc_tag\\.o",
  "PathPrefix": "mm/"
}

Results:
{
  "Output": "mm/Makefile=150=obj-$(CONFIG_LAZY_MMU_MODE_KUNIT_TEST) += tests/lazy_mmu_mode_kunit.o\nmm/Makefile:151:obj-$(CONFIG_MEM_ALLOC_PROFILING) += alloc_tag.o\n"
}

15/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28598
							output: 30
							thoughts: 100
						

Thoughts:
Okay, here's my summary, tailored as requested:

**Memory Management Configuration - A Quick Scan**

Alright, let's see, I need to configure this kernel. First thought is, I need to enable some profiling for memory allocation, so let's check `mm/alloc_tag.c` and make sure `CONFIG_MEM_ALLOC_PROFILING` is enabled. Seems logical. Then, let's move on and consider `compaction.c`. I'll want to be sure `CONFIG_COMPACTION` is properly set, of course. Transparency is always key, so I'll next think about `huge_memory.c` and `CONFIG_TRANSPARENT_HUGEPAGE`. I should probably ensure that is enabled, too, especially if I'm trying to optimize performance. Next, I'll need to look at `hugetlb.c` to see if `CONFIG_HUGETLB_PAGE` is correctly configured. And finally, before moving on, I need to check `hugetlb_cma.c`, as well, and make sure that one is up to snuff. That covers the major aspects I need to quickly glance over.



16/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "hugetlb_cma\\.o",
  "PathPrefix": "mm/"
}

Results:
{
  "Output": "mm/Makefile=83=ifdef CONFIG_CMA\nmm/Makefile:84:obj-$(CONFIG_HUGETLBFS)\t+= hugetlb_cma.o\nmm/Makefile-85-endif\n"
}

17/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 29041
							output: 31
							thoughts: 14
						

Thoughts:
**Considering Memory Allocation Strategies**

Okay, so I'm thinking about this memory allocation issue... where can I start? Right, let's explore the virtual memory mapping situation. I should think about `hugetlb_vmemmap.c`. What does the code in that file do, and is this relevant to the current problem? I know it deals with huge pages, but how is it dealing with memory mapping? Is there any potential there for this issue? Gotta dig deeper into that one.



18/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "hugetlb_vmemmap\\.o",
  "PathPrefix": "mm/"
}

Results:
{
  "Output": "mm/Makefile=85=endif\nmm/Makefile:86:obj-$(CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP)\t+= hugetlb_vmemmap.o\nmm/Makefile-87-obj-$(CONFIG_NUMA) \t+= mempolicy.o\n"
}

19/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 29271
							output: 28
							thoughts: 11
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Considering `hwpoison-inject.c`**

Alright, let's zoom in on this `hwpoison-inject.c` file. Given my expertise in [**User can fill in relevant expertise, e.g., memory management, kernel internals, error handling**], the immediate question that pops into my head is: what's the purpose of this particular tool? Is it designed for testing, debugging, or perhaps even live injection of hardware errors for specific analysis? Understanding its intended use case is paramount.

I'm thinking about the implications of injecting hardware-level errors. This means we're likely simulating or forcing memory corruption, perhaps at the page level. What kind of checks are incorporated? Does it account for possible race conditions during the injection process? Has it been rigorously tested to ensure it doesn't destabilize the system more than intended, or that it doesn't mask other underlying issues? I'd need to scrutinize the error handling. Is the injection predictable and controlled, or might it inadvertently trigger cascading failures or data loss?

I'd want to dig into the implementation details immediately. I'd want to know how the injection is achieved, looking specifically at where the hardware error is injected. Is it by manipulating page tables? Using MSRs? Or some other, more exotic method? And what about the error reporting path? Is the tool designed to trigger the standard kernel panic/Oops mechanisms, or does it attempt more graceful error handling?
Furthermore, I'm already wondering about compatibility. Does it only work on specific hardware architectures or is it designed to be as general as possible? What are the implications for NUMA systems or systems with complex memory configurations? Are there any documented limitations or known bugs? Does it offer fine-grained control over injection locations and types, or is it a more blunt instrument?
I'd need to assess its impact on the system, taking into account any potential for performance degradation. And finally, I'm thinking about the ethical implications. While invaluable for testing, this type of tool must be handled with utmost care and a clear understanding of the risks involved. Any use in production systems, even for diagnostic purposes, would demand very careful consideration.



20/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "hwpoison-inject\\.o",
  "PathPrefix": "mm/"
}

Results:
{
  "Output": "mm/Makefile=113=obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o\nmm/Makefile:114:obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o\nmm/Makefile-115-obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o\n"
}

21/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 29873
							output: 27
							thoughts: 109
						

Thoughts:
**Considering Memory Management Aspects**

Okay, let's break this down. I need to consider various memory management aspects within this context. My immediate thoughts go to specific files and their associated kernel configurations. First, I'm thinking about `ksm.c` and if its functionality is enabled via `CONFIG_KSM`. That's a crucial piece, if shared memory is even in play.

Next, `memory-failure.c` - naturally, I'm asking myself if `CONFIG_MEMORY_FAILURE` is set, and how this relates to any overall memory protection or error handling considerations.

Following that, `memory_hotplug.c` is on my mind, which would be governed by `CONFIG_MEMORY_HOTPLUG`. I need to understand if memory is dynamically being added or removed, and how that impacts my analysis.

The next thing on the list is `migrate.c`, and that obviously makes me check for `CONFIG_MIGRATION`.

Finally, and this feels interesting because it's a bit less direct, what about `page_isolation.c`? That one has me thinking about `CONFIG_PAGE_REPORTING` or perhaps, again, `CONFIG_MIGRATION`, because isolation is often related to migration. I'd better confirm what I'm thinking, so I'll check `page_isolation.o`. It's a key part of the investigation.



22/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "page_isolation\\.o",
  "PathPrefix": "mm/"
}

Results:
{
  "Output": "mm/Makefile=118=obj-$(CONFIG_PAGE_OWNER) += page_owner.o\nmm/Makefile:119:obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o\nmm/Makefile-120-obj-$(CONFIG_ZSMALLOC)\t+= zsmalloc.o\n"
}

23/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30394
							output: 32
							thoughts: 1554
						

Thoughts:
**Fuzzing Focus: Decoupling `struct folio` from `struct page`**

Okay, let's break this down. We're looking at a memory management refactoring, specifically related to the `struct folio` and `struct page` decoupling. The initial trigger was the `CONFIG_MEMORY_ISOLATION`, `CONFIG_PAGE_OWNER`, `CONFIG_USERFAULTFD`, `CONFIG_GUP_TEST`, and `CONFIG_ZONE_DEVICE` configurations. These are relevant contexts, but the core issue seems to revolve around changes across `mm/filemap.c` and `mm/shmem.c`.

The key bug involved a subtle error pointer corruption. Previously, `&folio->page` was returning an incorrect pointer when `folio` was an error pointer, due to the implicit offset to `page` not being handled correctly. This was coincidentally working but was fragile. The fix involves replacing those instances with `folio_page(folio, 0)` or `ERR_CAST`. So, it seems like a straightforward bug fix, right?

But why the broad refactoring? The commit message (or diff) is where the money is. The change is happening because `struct folio` is being decoupled from `struct page`. That means we are looking at a lot of core memory management work. The commit also alters assertions with `VM_BUG_ON_FOLIO`, and `VM_WARN_ON_ONCE_FOLIO`.

Now, the fuzzing strategy. With `WorthFuzzing=true`, we need to pick specific kernel functions. We need to avoid ubiquitous lifecycle hot-paths, and we need to target specific feature logic and entrypoints. So, let's filter out the usual suspects: `free_unref_folios`, `__folio_put`, `finish_fault`, `wp_page_copy`, `do_cow_fault`, `do_swap_page`, `filemap_map_order0_folio`, `filemap_unaccount_folio`, `folio_add_new_anon_rmap`. They are ALL page fault or deallocation related.

Instead, let's focus on the feature-specific changes. Looking at the code, we've got:

1.  **Folio Splitting**: `folio_split`, `split_folio_to_list`, and `folio_split_unmapped` in `mm/huge_memory.c`. These are non-ubiquitous, and are THP/large folio splitting functions. Also `move_pages_huge_pmd` and `zap_huge_pmd` in mm/huge_memory.c. They're all non-static symbols. Excellent targets.

2.  **Userfaultfd**: We have `move_pages` in `userfaultfd.c`. The entrypoint might be `userfaultfd_ioctl` or `userfaultfd_move` in `fs/userfaultfd.c` or `mm/userfaultfd.c`. This is where we will look next!



24/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "userfaultfd_move",
  "PathPrefix": "mm/userfaultfd.c"
}

Results:
{
  "Output": "mm/userfaultfd.c=4507=static inline unsigned int uffd_ctx_features(__u64 user_features)\n--\nmm/userfaultfd.c-4515-\nmm/userfaultfd.c:4516:static int userfaultfd_move(struct userfaultfd_ctx *ctx,\nmm/userfaultfd.c-4517-\t\t\t    unsigned long arg)\n--\nmm/userfaultfd.c=4644=static long userfaultfd_ioctl(struct file *file, unsigned cmd,\n--\nmm/userfaultfd.c-4672-\tcase UFFDIO_MOVE:\nmm/userfaultfd.c:4673:\t\tret = userfaultfd_move(ctx, arg);\nmm/userfaultfd.c-4674-\t\tbreak;\n"
}

25/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 32836
							output: 23
							thoughts: 146
						

Thoughts:
**Analyzing `move_pages` in the Kernel**

Okay, so I'm looking at `move_pages` within the context of `mm/userfaultfd.c`. The first thing that jumps out is that it's declared `static`. That immediately flags it as potentially inlined by the compiler. It's a common optimization. I need to know for sure. I'm going to check the definition directly... aha, it's over 100 lines long! No way that's being inlined. It's a distinct symbol, no doubt. The caller is `userfaultfd_move`, as expected.

Now, a new thought pops into my head... could this `move_pages` be considered a FocusSymbol? Could it be a point of analysis or a focal point for deeper investigation? And then it hits me! "move_pages" is also the name of a *system call*, `sys_move_pages`! I need to determine if there's any ambiguity here. I'm going to cross-reference it now with both `kernel/sys.c` (where syscall definitions usually reside) and `mm/migrate.c`, the migration code, to see if there's any conflict in names or definitions. It's crucial to be precise when dealing with kernel-level functions.



26/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "SYSCALL_DEFINE.*move_pages"
}

Results:
{
  "Output": "mm/migrate.c=2604=static int kernel_move_pages(pid_t pid, unsigned long nr_pages,\n--\nmm/migrate.c-2633-\nmm/migrate.c:2634:SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,\nmm/migrate.c-2635-\t\tconst void __user * __user *, pages,\n--\ntools/testing/selftests/kvm/include/numaif.h=23=KVM_SYSCALL_DEFINE(migrate_pages, 4, int, pid, unsigned long, maxnode,\n--\ntools/testing/selftests/kvm/include/numaif.h-25-\ntools/testing/selftests/kvm/include/numaif.h:26:KVM_SYSCALL_DEFINE(move_pages, 6, int, pid, unsigned long, count, void *, pages,\ntools/testing/selftests/kvm/include/numaif.h-27-\t\t   const int *, nodes, int *, status, int, flags);\n"
}

27/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 33568
							output: 50
							thoughts: 733
						

Thoughts:
**Fuzzing Target Refinement: Focusing on Memory Management Primitives**

Okay, so I'm diving into potential fuzzing targets within the Linux kernel, specifically around memory management. My initial observation is that `mm/migrate.c` defines `SYSCALL_DEFINE6(move_pages)` which gets either `__x64_sys_move_pages` or `sys_move_pages`. That's a good starting point, but I also see a static function named `move_pages` in `mm/userfaultfd.c`, so I'll keep an eye out for any naming conflicts and usage patterns.

Now, let's zoom in on `mm/migrate.c`. I've checked the functions touched in this file and I'm noting `putback_movable_pages`, `isolate_folio_to_list`, `migrate_folio_undo_dst`, `migrate_folio_done`, `migrate_folio_unmap`, `migrate_folio_move`, and `migrate_pages_batch`. `isolate_folio_to_list` and `putback_movable_pages` are non-static and exported, meaning they're accessible outside the file.

Next, I'm going through the other likely files:

*   `mm/hugetlb.c`: Here I find functions like `free_huge_folio`, `demote_free_hugetlb_folios`, and `hugetlb_wp`.
*   `mm/ksm.c`: Key functions here are `folio_stable_node`, `cmp_and_merge_page`, `write_protect_page`, `stable_tree_search`, and `stable_tree_insert`.
*   `mm/alloc_tag.c`: I spot `pgalloc_tag_split` and `pgalloc_tag_swap`.
*   `mm/compaction.c`: This one yields `compaction_alloc_noprof` and `compaction_free`.
*   `mm/shmem.c`: I'll note `shmem_read_mapping_page_gfp`.
*   `mm/memory-failure.c`: I identify `mf_generic_kill_procs` and `__get_hwpoison_page`.
*   `mm/page_owner.c`: The key functions here are `__folio_copy_owner` and `__folio_set_owner_migrate_reason`.

Now, I need to pinpoint the most direct, specific, and less ubiquitous targets. I'm thinking of the following:

1.  `split_folio_to_list` - The THP splitting entrypoint in mm/huge_memory.c.
2.  `folio_split` - Another THP splitting entrypoint in mm/huge_memory.c.
3.  `move_pages_huge_pmd` - PMD movement in mm/huge_memory.c.
4.  `pgalloc_tag_split` - Allocation profiling split in mm/alloc_tag.c.
5.  `pgalloc_tag_swap` - Allocation profiling swap in mm/alloc_tag.c.
6.  `compaction_alloc_noprof` / `compaction_free` - The Compaction allocator/freer in mm/compaction.c
7.  `isolate_folio_to_list` - Page migration isolation in mm/migrate.c.
8.  `hugetlb_wp` - HugeTLB copy-on-write fault in mm/hugetlb.c.
9.  `demote_free_hugetlb_folios` - HugeTLB demotion in mm/hugetlb.c.

I have to make sure my selected targets, like `split_folio_to_list`, `folio_split`, and `move_pages_huge_pmd`, are not static, or are exported. Let's make sure they are accessible from other parts of the kernel. I should verify that.



28/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "(folio_split|split_folio_to_list|move_pages_huge_pmd)\\(",
  "PathPrefix": "mm/huge_memory.c"
}

Results:
{
  "Output": "mm/huge_memory.c=2838=int change_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,\n--\nmm/huge_memory.c-2884- */\nmm/huge_memory.c:2885:int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval,\nmm/huge_memory.c-2886-\t\t\tstruct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,\n--\nmm/huge_memory.c=4123=static int __folio_freeze_split_file(struct folio *folio,\n--\nmm/huge_memory.c-4282-/**\nmm/huge_memory.c:4283: * __folio_split() - split a folio at @split_at to a @new_order folio\nmm/huge_memory.c-4284- * @folio: folio to split\n--\nmm/huge_memory.c-4302- */\nmm/huge_memory.c:4303:static int __folio_split(struct folio *folio, unsigned int new_order,\nmm/huge_memory.c-4304-\t\tstruct page *split_at, struct page *lock_at,\n--\nmm/huge_memory.c=4448=int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list,\n--\nmm/huge_memory.c-4452-\nmm/huge_memory.c:4453:\treturn __folio_split(folio, new_order, folio_page(folio, 0), page, list,\nmm/huge_memory.c-4454-\t\t\t     SPLIT_TYPE_UNIFORM);\n--\nmm/huge_memory.c-4457-/**\nmm/huge_memory.c:4458: * folio_split() - split a folio at @split_at to a @new_order folio\nmm/huge_memory.c-4459- * @folio: folio to split\n--\nmm/huge_memory.c-4480- */\nmm/huge_memory.c:4481:int folio_split(struct folio *folio, unsigned int new_order,\nmm/huge_memory.c-4482-\t\tstruct page *split_at, struct list_head *list)\nmm/huge_memory.c-4483-{\nmm/huge_memory.c:4484:\treturn __folio_split(folio, new_order, split_at, folio_page(folio, 0),\nmm/huge_memory.c-4485-\t\t\t     list, SPLIT_TYPE_NON_UNIFORM);\n--\nmm/huge_memory.c=4498=unsigned int min_order_for_split(struct folio *folio)\n--\nmm/huge_memory.c-4514-\nmm/huge_memory.c:4515:int split_folio_to_list(struct folio *folio, struct list_head *list)\nmm/huge_memory.c-4516-{\n--\nmm/huge_memory.c=4784=static int split_huge_pages_pid(int pid, unsigned long vaddr_start,\n--\nmm/huge_memory.c-4876-\t\t\t\t\t\t\t   in_folio_offset);\nmm/huge_memory.c:4877:\t\t\tif (!folio_split(folio, target_order, split_at, NULL))\nmm/huge_memory.c-4878-\t\t\t\tsplit++;\n--\nmm/huge_memory.c=4901=static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,\n--\nmm/huge_memory.c-4952-\t\t\t\t\t\t\t   in_folio_offset);\nmm/huge_memory.c:4953:\t\t\tif (!folio_split(folio, target_order, split_at, NULL))\nmm/huge_memory.c-4954-\t\t\t\tsplit++;\n"
}

29/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36257
							output: 36
							thoughts: 68
						

Thoughts:
Here's my analysis of the provided code snippets:

**Identifying Key Functions and Potential Optimization Points**

Okay, so I'm looking at `huge_memory.c` and immediately see some potentially useful, non-static symbols: `folio_split`, `split_folio_to_list`, and `move_pages_huge_pmd`. The fact that they're not static is interesting. That suggests they're intended for wider use and that I might be able to leverage them for some sort of optimization or analysis. My initial thought is to figure out the context of these functions, their relationships with other memory management components, and how they perform.

Next, I'll switch my focus to `mm/alloc_tag.c` to examine `pgalloc_tag_split` and `pgalloc_tag_swap`. My immediate concern is if there's any interplay between those two functions and the earlier ones. Are these tags somehow related to folio splitting or moving pages? Are they used in conjunction with huge pages or other large memory allocations? The `pgalloc` prefix is a strong clue that it's related to page allocation, and tags, so I'm thinking they are involved in marking or managing pages within those larger allocations. I have a hunch there might be some useful information to be found there.



30/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "pgalloc_tag_(split|swap)",
  "PathPrefix": "mm/alloc_tag.c"
}

Results:
{
  "Output": "mm/alloc_tag.c=487=size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)\n--\nmm/alloc_tag.c-527-\nmm/alloc_tag.c:528:void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)\nmm/alloc_tag.c-529-{\n--\nmm/alloc_tag.c-553-\nmm/alloc_tag.c:554:void pgalloc_tag_swap(struct folio *new, struct folio *old)\nmm/alloc_tag.c-555-{\n"
}

31/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36814
							output: 32
							thoughts: 44
						

Thoughts:
Here's my take on those thoughts:

**Concerning Memory Allocation and Migration**

Okay, so I'm looking at `pgalloc_tag_split` and `pgalloc_tag_swap`. The fact that they're non-static and *modified* is immediately a flag. I need to understand the implications of that – why aren't they static? What's the context? Are they intended to be used externally? Are they core to some specific allocation path? The modification is key; it screams "pay attention, something subtle or important is happening here."

Now, what about `isolate_folio_to_list` in `mm/migrate.c`? That function is involved in moving pages, right? That's right - I need to correlate the role of `isolate_folio_to_list`, in its relationship to the allocation paths that might be calling `pgalloc_tag_split` or `pgalloc_tag_swap`. Is there some interplay between migrating pages and tagged allocation or swapping? I'm wondering if there's a connection between memory migration and these tagged allocation mechanisms that I'm seeing. Perhaps there's a performance optimization or a subtle handling of tagged pages during migration. Maybe these tagged functions are used in the migration process somehow. I need to track down the callers and understand the data flows to grasp the bigger picture.



32/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "isolate_folio_to_list",
  "PathPrefix": "mm/migrate.c"
}

Results:
{
  "Output": "mm/migrate.c=258=void putback_movable_pages(struct list_head *l)\n--\nmm/migrate.c-279-/* Must be called with an elevated refcount on the non-hugetlb folio */\nmm/migrate.c:280:bool isolate_folio_to_list(struct folio *folio, struct list_head *list)\nmm/migrate.c-281-{\n"
}

33/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 37289
							output: 37
							thoughts: 110
						

Thoughts:
**Examining Static Functions Across Memory Management**

Okay, so I'm focusing on static functions within the kernel's memory management code. I've noted that `isolate_folio_to_list` and `putback_movable_pages` are non-static, which is good to know for context. My current line of thinking is driven by finding other functions which may have some similarities. 

Now, I'm thinking about `compaction_alloc_noprof` and `compaction_free` in `mm/compaction.c`. I have to double-check quickly, are those functions actually static? Yes, they are. And, if I'm thinking about static functions and memory management, then I should also look at hugepages. So, what about `free_huge_folio` and `demote_free_hugetlb_folios` in `mm/hugetlb.c`? Okay, let's open that file and confirm and review.



34/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "demote_free_hugetlb_folios",
  "PathPrefix": "mm/hugetlb.c"
}

Results:
{
  "Output": "mm/hugetlb.c=3786=static int set_max_huge_pages(struct hstate *h, unsigned long count, int nid,\n--\nmm/hugetlb.c-3974-\nmm/hugetlb.c:3975:static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,\nmm/hugetlb.c-3976-\t\t\t\t       struct list_head *src_list)\n--\nmm/hugetlb.c=4035=long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,\n--\nmm/hugetlb.c-4101-\t\tif (!list_empty(\u0026list))\nmm/hugetlb.c:4102:\t\t\trc = demote_free_hugetlb_folios(src, dst, \u0026list);\nmm/hugetlb.c-4103-\t\tif (!list_empty(\u0026surplus_list)) {\n--\nmm/hugetlb.c-4105-\nmm/hugetlb.c:4106:\t\t\ttmp_rc = demote_free_hugetlb_folios(src, dst, \u0026surplus_list);\nmm/hugetlb.c-4107-\t\t\tif (rc \u003e= 0)\n"
}

35/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 37981
							output: 33
							thoughts: 239
						

Thoughts:
**Investigating Huge Page Demotion and Related Functions**

Okay, so `demote_pool_huge_page` ultimately calls `demote_free_hugetlb_folios`. That's the core of the function. But I need to make sure I'm considering all relevant paths. What about `hugetlb_cma_free_frozen_folio`? Is it used in a similar context? Time to check `hugetlb_cma.c`. Yep, `void hugetlb_cma_free_frozen_folio(struct folio *folio)` is *not* static, which means it could be called from elsewhere. I need to keep that in mind as a potential point of interaction.

Let's expand the scope a bit. What about the rmap functions? I'll check `mm/rmap.c` next. Are `hugetlb_add_anon_rmap` and `hugetlb_add_new_anon_rmap` non-static? Yes, they are! Important for mapping these folios. I need to be aware of how they're used.

Okay, now let's shift gears to `userfaultfd.c`. Specifically, I'm thinking about the interactions between huge pages and `userfaultfd`. Let's see... `move_pages` in `mm/userfaultfd.c` is static, which is called by `userfaultfd_move`. Wait a minute... `userfaultfd_move` *itself* is also static, and called by `userfaultfd_ioctl`. Which means that *specifically* `move_pages` is encapsulated within `userfaultfd_move` which is not externally accessible. However, I need to be absolutely certain. Is `move_pages` *or any other function* in `mm/userfaultfd.c` exported or non-static? It seems like I need to double-check `mm/userfaultfd.c` thoroughly.



36/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "move_pages_ptes",
  "PathPrefix": "mm/userfaultfd.c"
}

Results:
{
  "Output": "mm/userfaultfd.c=1436=static int move_zeropage_pte(struct mm_struct *mm,\n--\nmm/userfaultfd.c-1475- */\nmm/userfaultfd.c:1476:static long move_pages_ptes(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd,\nmm/userfaultfd.c-1477-\t\t\t    struct vm_area_struct *dst_vma,\n--\nmm/userfaultfd.c=1978=static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,\n--\nmm/userfaultfd.c-2112-\nmm/userfaultfd.c:2113:\t\t\tret = move_pages_ptes(mm, dst_pmd, src_pmd,\nmm/userfaultfd.c-2114-\t\t\t\t\t      dst_vma, src_vma, dst_addr,\n"
}

37/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38930
							output: 38
							thoughts: 84
						

Thoughts:
Okay, let's dive into this.

**Investigating `shmem_read_mapping_page_gfp`**

Right, let's get down to brass tacks. I'm taking a look at `shmem_read_mapping_page_gfp` – a function name I'm familiar with but want to verify the context of.  Let's pull up the source for `mm/shmem.c`.  The key thing I'm immediately interested in is: `struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp)`. Now, the important question – is this function declared non-static? I need to know its visibility within the kernel. If it's static, it's limited to that file and I need to keep looking, but if it is not static, then it's visible to the kernel as a whole.



38/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "shmem_read_mapping_page_gfp\\(",
  "PathPrefix": "mm/shmem.c"
}

Results:
{
  "Output": "mm/shmem.c=6186=EXPORT_SYMBOL_GPL(shmem_read_folio_gfp);\nmm/shmem.c-6187-\nmm/shmem.c:6188:struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,\nmm/shmem.c-6189-\t\t\t\t\t pgoff_t index, gfp_t gfp)\n"
}

39/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 39378
							output: 34
							thoughts: 119
						

Thoughts:
**A Curious Case of Page Retrieval**

Okay, so `shmem_read_mapping_page_gfp` isn't static, which immediately piques my interest. And, look at this! There's an actual bug fix in this patch: the return was changed from `&folio->page` to `ERR_CAST(folio)`. That's a classic pointer error, and the fix suggests a misunderstanding of how the folio/page relationship is handled here. I'll need to dig into this.

Now, where else might this pattern exist? Let's see... I remember seeing a similar correction in `do_read_cache_page` in `mm/filemap.c`. Yep, there it is! Same fix! Now, the question is, what non-static functions are calling `do_read_cache_page`? I need to trace the call graph to understand the broader implications of this correction. Time to dive back into `mm/filemap.c`. Let's see what's what.



40/2 2026/09/30 22:02 tool grepper
0m Args:
{
  "Expression": "do_read_cache_page\\(",
  "PathPrefix": "mm/filemap.c"
}

Results:
{
  "Output": "mm/filemap.c=4233=EXPORT_SYMBOL(mapping_read_folio_gfp);\nmm/filemap.c-4234-\nmm/filemap.c:4235:static struct page *do_read_cache_page(struct address_space *mapping,\nmm/filemap.c-4236-\t\tpgoff_t index, filler_t *filler, struct file *file, gfp_t gfp)\n--\nmm/filemap.c=4246=struct page *read_cache_page(struct address_space *mapping,\n--\nmm/filemap.c-4248-{\nmm/filemap.c:4249:\treturn do_read_cache_page(mapping, index, filler, file,\nmm/filemap.c-4250-\t\t\tmapping_gfp_mask(mapping));\n--\nmm/filemap.c=4269=struct page *read_cache_page_gfp(struct address_space *mapping,\n--\nmm/filemap.c-4272-{\nmm/filemap.c:4273:\treturn do_read_cache_page(mapping, index, NULL, NULL, gfp);\nmm/filemap.c-4274-}\n"
}

41/2 2026/09/30 22:02 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 40069
							output: 22
							thoughts: 417
						

Thoughts:
**Analyzing Potential Conflicts and Dependencies in Kernel Memory Management**

Okay, so I'm looking into how `read_cache_page` and `read_cache_page_gfp` are implemented, and I see they both call `do_read_cache_page`. I need to understand how these functions interact with the larger kernel memory management system. Let me start by checking a few functions that could be related.

First, I'm checking `free_zone_device_folio` in `mm/memremap.c`. Good, it's non-static, so it's potentially visible and could be used elsewhere. Then, let's look at `page_is_unmovable` in `mm/page_isolation.c`. Again, non-static. This is another point of potential interaction to keep in mind. Also, I'll review `__folio_copy_owner` in `mm/page_owner.c`, which is also non-static, so I'll keep this in mind. Finally, `__split_huge_page_to_list_to_order` in `mm/huge_memory.c` is non-static as well.

Now, let's step back and consider the bigger picture. I need to be aware of the configuration options that might influence how these functions behave. This patch touches a variety of files that are controlled by these Kconfig options. Specifically, I'm noting `TRANSPARENT_HUGEPAGE`, which affects huge memory management in files like `huge_memory.c` and `khugepaged.c`. `HUGETLB_PAGE` is also in play, affecting `hugetlb.c` and `hugetlb_vmemmap.c`. There's also `MEM_ALLOC_PROFILING`, handled in `alloc_tag.c`, `MIGRATION` impacting `migrate.c`, `USERFAULTFD`, `KSM`, `PAGE_OWNER`, and finally, `MEMORY_FAILURE`.

Okay, now it's time to check the dependencies of these configs in Kconfig. This is where the real complexity lies, where I will have to ensure that my changes aren't going to break any dependencies!
Let's see the dependencies for `MEM_ALLOC_PROFILING`...



42/2 2026/09/30 22:03 tool grepper
0m Args:
{
  "Expression": "config MEM_ALLOC_PROFILING"
}

Results:
{
  "Output": "mm/Kconfig.debug=272=config PER_VMA_LOCK_STATS\n--\nmm/Kconfig.debug-283-\nmm/Kconfig.debug:284:config MEM_ALLOC_PROFILING\nmm/Kconfig.debug-285-\tbool \"Enable memory allocation profiling\"\n--\nmm/Kconfig.debug-296-\nmm/Kconfig.debug:297:config MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\nmm/Kconfig.debug-298-\tbool \"Enable memory allocation profiling by default\"\n--\nmm/Kconfig.debug-301-\nmm/Kconfig.debug:302:config MEM_ALLOC_PROFILING_DEBUG\nmm/Kconfig.debug-303-\tbool \"Memory allocation profiler debugging\"\n"
}

43/2 2026/09/30 22:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41205
							output: 34
							thoughts: 22
						

Thoughts:
Okay, let's dive into this. I'm going to take a look at the `mm/Kconfig.debug` file, specifically lines 280-310. I know this file holds crucial configuration options related to memory management debugging within the kernel, so this section probably deals with some specific aspects of memory debugging. Given the context, I'm expecting to find features that allow for more detailed instrumentation, maybe options to enable specific checks, or potentially configurations related to debugging tools like those dealing with memory corruption or leaks. My expertise lets me infer all this from the filename and location, so I'll be very quick at parsing this given my deep understanding of the kernel internals. I'm keen to see if this corresponds to options that I can deploy when dealing with issues of a low-level nature.



44/2 2026/09/30 22:03 tool read-file
0m Args:
{
  "File": "mm/Kconfig.debug",
  "FirstLine": 280,
  "LineCount": 35
}

Results:
{
  "Contents": " 280:\t\t  overhead in the page fault path.\n 281:\t\n 282:\t\t  If in doubt, say N.\n 283:\t\n 284:\tconfig MEM_ALLOC_PROFILING\n 285:\t\tbool \"Enable memory allocation profiling\"\n 286:\t\tdefault n\n 287:\t\tdepends on MMU\n 288:\t\tdepends on PROC_FS\n 289:\t\tselect CODE_TAGGING\n 290:\t\tselect PAGE_EXTENSION\n 291:\t\tselect SLAB_OBJ_EXT\n 292:\t\thelp\n 293:\t\t  Track allocation source code and record total allocation size\n 294:\t\t  initiated at that code location. The mechanism can be used to track\n 295:\t\t  memory leaks with a low performance and memory impact.\n 296:\t\n 297:\tconfig MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\n 298:\t\tbool \"Enable memory allocation profiling by default\"\n 299:\t\tdefault y\n 300:\t\tdepends on MEM_ALLOC_PROFILING\n 301:\t\n 302:\tconfig MEM_ALLOC_PROFILING_DEBUG\n 303:\t\tbool \"Memory allocation profiler debugging\"\n 304:\t\tdefault n\n 305:\t\tdepends on MEM_ALLOC_PROFILING\n 306:\t\tselect MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\n 307:\t\thelp\n 308:\t\t  Adds warnings with helpful error messages for memory allocation\n 309:\t\t  profiling.\n"
}

45/2 2026/09/30 22:03 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41840
							output: 261
							thoughts: 1357
						

Thoughts:
**Fuzzing Verdict Rationale: Memory Management Code Review**

Okay, let's break this down. First, I wanted to map out the relevant configuration options. I looked at `TRANSPARENT_HUGEPAGE` and `HUGETLB_PAGE` in `mm/Kconfig`, noting their dependencies, which are pretty standard. Then I considered the key configurations: `CONFIG_MEM_ALLOC_PROFILING`, `CONFIG_TRANSPARENT_HUGEPAGE`, `CONFIG_HUGETLB_PAGE`, `CONFIG_USERFAULTFD`, `CONFIG_MIGRATION`, `CONFIG_KSM`, and `CONFIG_PAGE_OWNER`. I wanted to get a feel for what areas are being touched and what's enabled.

Next, I zeroed in on the "FocusSymbols" – the functions that seem most directly impacted. I initially considered `split_folio_to_list`, `folio_split`, `move_pages_huge_pmd`, `pgalloc_tag_split`, `pgalloc_tag_swap`, `isolate_folio_to_list`, `shmem_read_mapping_page_gfp`, and `hugetlb_cma_free_frozen_folio`. Then, I performed a sanity check on all the symbols, verifying where they are defined. I noticed that `compaction_alloc_noprof` and `compaction_free` were modified too. The key distinction is that while `compaction_alloc_noprof` and `compaction_free` are static, they're called as function pointers, and therefore have visible symbols in the symbol table unless inlined.

I did a second pass to determine if these symbols are ubiquitous. I checked the call paths of these symbols and confirmed that they are non-ubiquitous in various scenarios, relating to THP split, mremap, page migration, etc.

I also looked at specific entrypoints, like `userfaultfd_move` and quickly confirmed that `move_pages_huge_pmd` is the key for huge PMD movement, and userfaultfd move is specific. I also quickly looked at modules like `gup_test.c` and `hwpoison_inject` to confirm that they are not relevant.

Finally, I reviewed the config dependencies. `MEM_ALLOC_PROFILING` enables `alloc_tag.c`. `TRANSPARENT_HUGEPAGE` enables huge_memory.c and its functions. `HUGETLB_PAGE` enables `hugetlb.c`. `USERFAULTFD` enables `userfaultfd.c`. `MIGRATION` enables `isolate_folio_to_list` and compaction functions. I verified that none of these configs use the `CONFIG_` prefix.

In short, the patch touches core memory management code across multiple files, meaning we need to fuzz. It's refactoring direct access to `folio->page` to `folio_page(folio, 0)` or fixing return values with `ERR_CAST()`, and updating assertion macros like `VM_BUG_ON_FOLIO`. These changes are fundamental to kernel logic and state manipulation during folio splitting, page migration, compaction, and userfaultfd move operations. That warrants fuzzing to prevent regressions or invariant violations in critical areas. Okay, that's everything. Time to call `set-results`.



46/2 2026/09/30 22:03 tool set-results
0m Args:
{
  "EnableConfigs": [
    "MEM_ALLOC_PROFILING",
    "TRANSPARENT_HUGEPAGE",
    "HUGETLB_PAGE",
    "USERFAULTFD",
    "MIGRATION"
  ],
  "FocusSymbols": [
    "split_folio_to_list",
    "folio_split",
    "move_pages_huge_pmd",
    "pgalloc_tag_split",
    "pgalloc_tag_swap",
    "isolate_folio_to_list",
    "shmem_read_mapping_page_gfp"
  ],
  "Reasoning": "The patch series modifies core memory management (mm/) subsystems, refactoring direct 'folio-\u003epage' references to 'folio_page(folio, 0)', correcting error returns (e.g. ERR_CAST in do_read_cache_page and shmem_read_mapping_page_gfp), altering list additions in compaction, and updating VM assertions (such as VM_BUG_ON_FOLIO). These modifications affect reachable MM paths including huge folio splitting, page migration, compaction, userfaultfd, and memory allocation profiling, making fuzzing valuable to detect regressions and violated invariants.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "MEM_ALLOC_PROFILING",
    "TRANSPARENT_HUGEPAGE",
    "HUGETLB_PAGE",
    "USERFAULTFD",
    "MIGRATION"
  ],
  "FocusSymbols": [
    "split_folio_to_list",
    "folio_split",
    "move_pages_huge_pmd",
    "pgalloc_tag_split",
    "pgalloc_tag_swap",
    "isolate_folio_to_list",
    "shmem_read_mapping_page_gfp"
  ],
  "Reasoning": "The patch series modifies core memory management (mm/) subsystems, refactoring direct 'folio-\u003epage' references to 'folio_page(folio, 0)', correcting error returns (e.g. ERR_CAST in do_read_cache_page and shmem_read_mapping_page_gfp), altering list additions in compaction, and updating VM assertions (such as VM_BUG_ON_FOLIO). These modifications affect reachable MM paths including huge folio splitting, page migration, compaction, userfaultfd, and memory allocation profiling, making fuzzing valuable to detect regressions and violated invariants.",
  "WorthFuzzing": true
}

47/1 2026/09/30 22:03 action If
0m Args:
{
  "WorthFuzzing": true
}

Results:
null

48/2 2026/09/30 22:03 agent kmsan-evaluator
0m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch series performs a mechanical refactoring across the core memory management subsystem (alloc_tag, compaction, filemap, gup, huge_memory, hugetlb, ksm, memory, migrate, page_alloc, rmap, etc.) replacing direct accesses to '\u0026folio-\u003epage' with the helper 'folio_page(folio, 0)', and replacing '\u0026folio-\u003epage' error returns with 'ERR_CAST(folio)'.\n\nAt the machine level, 'folio_page(folio, 0)' expands to '(\u0026(folio)-\u003epage + 0)', which is functionally and semantically identical to '\u0026folio-\u003epage'. The patch does not introduce new allocations, alter struct initialization or layout, modify memory copies to user space, or affect control flow based on uninitialized data. There are no risks of uninitialized memory access or kernel-to-user info-leaks. Any potential regression from page pointer manipulation would be caught by CONFIG_DEBUG_VM assertions, KASAN, or standard kernel debug facilities. A dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit e0b2f96dcac870e7cec69519979c25607faf5cb4
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Sep 30 22:01:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index 82e2c3448dcf2..c93efb224ce1b 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -534,7 +534,7 @@ void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)
 	if (!mem_alloc_profiling_enabled())
 		return;
 
-	tag = __pgalloc_tag_get(&folio->page);
+	tag = __pgalloc_tag_get(folio_page(folio, 0));
 	if (!tag)
 		return;
 
@@ -560,16 +560,16 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old)
 	if (!mem_alloc_profiling_enabled())
 		return;
 
-	tag_old = __pgalloc_tag_get(&old->page);
+	tag_old = __pgalloc_tag_get(folio_page(old, 0));
 	if (!tag_old)
 		return;
-	tag_new = __pgalloc_tag_get(&new->page);
+	tag_new = __pgalloc_tag_get(folio_page(new, 0));
 	if (!tag_new)
 		return;
 
-	if (!get_page_tag_ref(&old->page, &ref_old, &handle_old))
+	if (!get_page_tag_ref(folio_page(old, 0), &ref_old, &handle_old))
 		return;
-	if (!get_page_tag_ref(&new->page, &ref_new, &handle_new)) {
+	if (!get_page_tag_ref(folio_page(new, 0), &ref_new, &handle_new)) {
 		put_page_tag_ref(handle_old);
 		return;
 	}
diff --git a/mm/compaction.c b/mm/compaction.c
index f1b2060eb2016..d708d973250a4 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1845,7 +1845,6 @@ static void isolate_freepages(struct compact_control *cc)
 static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long data)
 {
 	struct compact_control *cc = (struct compact_control *)data;
-	struct folio *dst;
 	int order = folio_order(src);
 	bool has_isolated_pages = false;
 	int start_order;
@@ -1878,15 +1877,13 @@ static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long da
 
 		list_add(&freepage[size].lru, &cc->freepages[start_order]);
 	}
-	dst = (struct folio *)freepage;
-
-	post_alloc_hook(&dst->page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
-	set_page_refcounted(&dst->page);
+	post_alloc_hook(freepage, order, __GFP_MOVABLE, ALLOC_DEFAULT);
+	set_page_refcounted(freepage);
 	if (order)
-		prep_compound_page(&dst->page, order);
+		prep_compound_page(freepage, order);
 	cc->nr_freepages -= 1 << order;
 	cc->nr_migratepages -= 1 << order;
-	return page_rmappable_folio(&dst->page);
+	return page_rmappable_folio(freepage);
 }
 
 static struct folio *compaction_alloc(struct folio *src, unsigned long data)
@@ -1903,10 +1900,10 @@ static void compaction_free(struct folio *dst, unsigned long data)
 {
 	struct compact_control *cc = (struct compact_control *)data;
 	int order = folio_order(dst);
-	struct page *page = &dst->page;
+	struct page *page = folio_page(dst, 0);
 
 	if (folio_put_testzero(dst) && free_pages_prepare(page, order)) {
-		list_add(&dst->lru, &cc->freepages[order]);
+		list_add(&page->lru, &cc->freepages[order]);
 		cc->nr_freepages += 1 << order;
 	}
 	cc->nr_migratepages += 1 << order;
diff --git a/mm/filemap.c b/mm/filemap.c
index b74bc1e5015c6..02e0c2af594ca 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -156,7 +156,7 @@ static void filemap_unaccount_folio(struct address_space *mapping,
 	if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(folio_mapped(folio))) {
 		pr_alert("BUG: Bad page cache in process %s  pfn:%05lx\n",
 			 current->comm, folio_pfn(folio));
-		dump_page(&folio->page, "still mapped when deleted");
+		dump_page(folio_page(folio, 0), "still mapped when deleted");
 		dump_stack();
 		add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 
@@ -3888,7 +3888,7 @@ static vm_fault_t filemap_map_order0_folio(struct vm_fault *vmf,
 		unsigned long *rss)
 {
 	vm_fault_t ret = 0;
-	struct page *page = &folio->page;
+	struct page *page = folio_page(folio, 0);
 
 	if (PageHWPoison(page))
 		goto out;
@@ -4239,7 +4239,7 @@ static struct page *do_read_cache_page(struct address_space *mapping,
 
 	folio = do_read_cache_folio(mapping, index, filler, file, gfp);
 	if (IS_ERR(folio))
-		return &folio->page;
+		return ERR_CAST(folio);
 	return folio_file_page(folio, index);
 }
 
diff --git a/mm/folio.c b/mm/folio.c
index 35e242b48870b..978565add078e 100644
--- a/mm/folio.c
+++ b/mm/folio.c
@@ -103,7 +103,7 @@ void __folio_put(struct folio *folio)
 	page_cache_release(folio);
 	folio_unqueue_deferred_split(folio);
 	mem_cgroup_uncharge(folio);
-	free_frozen_pages(&folio->page, folio_order(folio));
+	free_frozen_pages(folio_page(folio, 0), folio_order(folio));
 }
 EXPORT_SYMBOL(__folio_put);
 
diff --git a/mm/gup.c b/mm/gup.c
index 8e9ef5ee7498c..1ce7ea5e7abb5 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -59,10 +59,11 @@ static inline void sanity_check_pinned_pages(struct page **pages,
 		    !folio_test_anon(folio))
 			continue;
 		if (!folio_test_large(folio) || folio_test_hugetlb(folio))
-			VM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(&folio->page), folio);
+			VM_WARN_ON_ONCE_FOLIO(!PageAnonExclusive(folio_page(folio, 0)),
+					      folio);
 		else
 			/* Either a PTE-mapped or a PMD-mapped THP. */
-			VM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(&folio->page) &&
+			VM_WARN_ON_ONCE_PAGE(!PageAnonExclusive(folio_page(folio, 0)) &&
 					     !PageAnonExclusive(page), page);
 	}
 }
@@ -2957,7 +2958,8 @@ static unsigned long gup_fast_pmd_leaf(pmd_t orig, pmd_t *pmdp,
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
-	if (!pmd_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) {
+	if (!pmd_write(orig) &&
+	    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
@@ -2999,7 +3001,8 @@ static unsigned long gup_fast_pud_leaf(pud_t orig, pud_t *pudp,
 		return 0;
 	}
 
-	if (!pud_write(orig) && gup_must_unshare(NULL, flags, &folio->page)) {
+	if (!pud_write(orig) &&
+	    gup_must_unshare(NULL, flags, folio_page(folio, 0))) {
 		gup_put_folio(folio, nr_pages, flags);
 		return 0;
 	}
diff --git a/mm/gup_test.c b/mm/gup_test.c
index ba74bf3f41048..337b58221c792 100644
--- a/mm/gup_test.c
+++ b/mm/gup_test.c
@@ -59,13 +59,15 @@ static void verify_dma_pinned(unsigned int cmd, struct page **pages,
 			if (WARN(!folio_maybe_dma_pinned(folio),
 				 "pages[%lu] is NOT dma-pinned\n", i)) {
 
-				dump_page(&folio->page, "gup_test failure");
+				dump_page(folio_page(folio, 0),
+					  "gup_test failure");
 				break;
 			} else if (cmd == PIN_LONGTERM_BENCHMARK &&
 				WARN(!folio_is_longterm_pinnable(folio),
 				     "pages[%lu] is NOT pinnable but pinned\n",
 				     i)) {
-				dump_page(&folio->page, "gup_test failure");
+				dump_page(folio_page(folio, 0),
+					  "gup_test failure");
 				break;
 			}
 		}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ddc631a388b93..58fbc4d4ddb8b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1664,7 +1664,8 @@ static vm_fault_t insert_pmd(struct vm_area_struct *vma, unsigned long addr,
 			entry = pmd_mkspecial(entry);
 		} else {
 			folio_get(fop.folio);
-			folio_add_file_rmap_pmd(fop.folio, &fop.folio->page, vma);
+			folio_add_file_rmap_pmd(fop.folio,
+						folio_page(fop.folio, 0), vma);
 			add_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PMD_NR);
 		}
 	} else {
@@ -1786,7 +1787,8 @@ static vm_fault_t insert_pud(struct vm_area_struct *vma, unsigned long addr,
 		entry = folio_mk_pud(fop.folio, vma->vm_page_prot);
 
 		folio_get(fop.folio);
-		folio_add_file_rmap_pud(fop.folio, &fop.folio->page, vma);
+		folio_add_file_rmap_pud(fop.folio,
+					folio_page(fop.folio, 0), vma);
 		add_mm_counter(mm, mm_counter_file(fop.folio), HPAGE_PUD_NR);
 	} else {
 		entry = pud_mkhuge(pfn_pud(fop.pfn, prot));
@@ -1935,7 +1937,7 @@ static void copy_huge_non_present_pmd(
 		 * folio_try_dup_anon_rmap_pmd does not fail for
 		 * device private entries.
 		 */
-		folio_try_dup_anon_rmap_pmd(src_folio, &src_folio->page,
+		folio_try_dup_anon_rmap_pmd(src_folio, folio_page(src_folio, 0),
 					    dst_vma, src_vma);
 	}
 
@@ -2487,7 +2489,7 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 
 	/* Present and device private folios are rmappable. */
 	if (is_present || is_device_private)
-		folio_remove_rmap_pmd(folio, &folio->page, vma);
+		folio_remove_rmap_pmd(folio, folio_page(folio, 0), vma);
 
 	if (folio_test_anon(folio)) {
 		add_mm_counter(mm, MM_ANONPAGES, -HPAGE_PMD_NR);
@@ -2572,7 +2574,7 @@ bool zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
 
 	spin_unlock(ptl);
 	if (is_present && folio)
-		tlb_remove_page_size(tlb, &folio->page, HPAGE_PMD_SIZE);
+		tlb_remove_page_size(tlb, folio_page(folio, 0), HPAGE_PMD_SIZE);
 	return true;
 }
 
@@ -2947,7 +2949,7 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
 	}
 	if (src_folio) {
 		if (folio_maybe_dma_pinned(src_folio) ||
-		    !PageAnonExclusive(&src_folio->page)) {
+		    !PageAnonExclusive(folio_page(src_folio, 0))) {
 			err = -EBUSY;
 			goto unlock_ptls;
 		}
@@ -3709,7 +3711,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
 	 * the flags from the original folio.
 	 */
 	for (i = new_nr_pages; i < nr_pages; i += new_nr_pages) {
-		struct page *new_head = &folio->page + i;
+		struct page *new_head = folio_page(folio, i);
 		/*
 		 * Careful: new_folio is not a "real" folio before we cleared PageTail.
 		 * Don't pass it around before clear_compound_head().
@@ -3806,7 +3808,7 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
 	if (new_order)
 		folio_set_order(folio, new_order);
 	else
-		ClearPageCompound(&folio->page);
+		ClearPageCompound(folio_page(folio, 0));
 }
 
 /**
@@ -3896,7 +3898,7 @@ static int __split_frozen_folio(struct folio *folio, int new_order,
 		}
 
 		folio_split_memcg_refs(folio, old_order, split_order);
-		split_page_owner(&folio->page, old_order, split_order);
+		split_page_owner(folio_page(folio, 0), old_order, split_order);
 		pgalloc_tag_split(folio, old_order, split_order);
 		__split_folio_to_order(folio, old_order, split_order);
 
@@ -4392,7 +4394,7 @@ int folio_split_unmapped(struct folio *folio, unsigned int new_order)
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_large(folio), folio);
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_anon(folio), folio);
 
-	return __folio_freeze_split_anon(folio, new_order, &folio->page,
+	return __folio_freeze_split_anon(folio, new_order, folio_page(folio, 0),
 					 false, NULL, SPLIT_TYPE_UNIFORM);
 }
 
@@ -4448,7 +4450,7 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list
 {
 	struct folio *folio = page_folio(page);
 
-	return __folio_split(folio, new_order, &folio->page, page, list,
+	return __folio_split(folio, new_order, folio_page(folio, 0), page, list,
 			     SPLIT_TYPE_UNIFORM);
 }
 
@@ -4479,8 +4481,8 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list
 int folio_split(struct folio *folio, unsigned int new_order,
 		struct page *split_at, struct list_head *list)
 {
-	return __folio_split(folio, new_order, split_at, &folio->page, list,
-			     SPLIT_TYPE_NON_UNIFORM);
+	return __folio_split(folio, new_order, split_at, folio_page(folio, 0),
+			     list, SPLIT_TYPE_NON_UNIFORM);
 }
 
 /**
@@ -4512,7 +4514,7 @@ unsigned int min_order_for_split(struct folio *folio)
 
 int split_folio_to_list(struct folio *folio, struct list_head *list)
 {
-	return split_huge_page_to_list_to_order(&folio->page, list, 0);
+	return split_huge_page_to_list_to_order(folio_page(folio, 0), list, 0);
 }
 
 /*
@@ -5186,12 +5188,13 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct folio *folio
 		if (!softleaf_is_migration_read(entry))
 			rmap_flags |= RMAP_EXCLUSIVE;
 
-		folio_add_anon_rmap_pmd(folio, &folio->page, vma, haddr, rmap_flags);
+		folio_add_anon_rmap_pmd(folio, folio_page(folio, 0), vma,
+					haddr, rmap_flags);
 	} else {
-		folio_add_file_rmap_pmd(folio, &folio->page, vma);
+		folio_add_file_rmap_pmd(folio, folio_page(folio, 0), vma);
 	}
 	VM_WARN_ON_ONCE(pmd_write(pmde) && folio_test_anon(folio) &&
-			!PageAnonExclusive(&folio->page));
+			!PageAnonExclusive(folio_page(folio, 0)));
 	set_pmd_at(mm, haddr, pvmw->pmd, pmde);
 
 	/* No need to invalidate - it was non-present before */
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a1b51251103b3..31ca8777ccbac 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1274,7 +1274,7 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,
 		if (folio_test_hwpoison(folio))
 			continue;
 
-		if (is_migrate_isolate_page(&folio->page))
+		if (is_migrate_isolate_page(folio_page(folio, 0)))
 			continue;
 
 		list_move(&folio->lru, &h->hugepage_activelist);
@@ -1511,7 +1511,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
 	if (folio_test_hugetlb_cma(folio))
 		hugetlb_cma_free_frozen_folio(folio);
 	else
-		free_frozen_pages(&folio->page, folio_order(folio));
+		free_frozen_pages(folio_page(folio, 0), folio_order(folio));
 }
 
 /*
@@ -1701,7 +1701,7 @@ void free_huge_folio(struct folio *folio)
 
 	hugetlb_set_folio_subpool(folio, NULL);
 	if (folio_test_anon(folio))
-		__ClearPageAnonExclusive(&folio->page);
+		__ClearPageAnonExclusive(folio_page(folio, 0));
 	folio->mapping = NULL;
 	restore_reserve = folio_test_hugetlb_restore_reserve(folio);
 	folio_clear_hugetlb_restore_reserve(folio);
@@ -3238,7 +3238,7 @@ static void __init hugetlb_folio_init_tail_vmemmap(struct folio *folio,
 	 */
 	for (pfn = head_pfn + start_page_number; pfn < end_pfn; page++, pfn++) {
 		__init_single_page(page, pfn, zone, nid);
-		prep_compound_tail(page, &folio->page, order);
+		prep_compound_tail(page, folio_page(folio, 0), order);
 		set_page_count(page, 0);
 	}
 }
@@ -3259,7 +3259,7 @@ static void __init hugetlb_folio_init_vmemmap(struct folio *folio,
 	ret = folio_ref_freeze(folio, 1);
 	VM_BUG_ON(!ret);
 	hugetlb_folio_init_tail_vmemmap(folio, h, 1, nr_pages);
-	prep_compound_head(&folio->page, huge_page_order(h));
+	prep_compound_head(folio_page(folio, 0), huge_page_order(h));
 }
 
 /*
@@ -4004,7 +4004,8 @@ static long demote_free_hugetlb_folios(struct hstate *src, struct hstate *dst,
 
 		list_del(&folio->lru);
 
-		split_page_owner(&folio->page, huge_page_order(src), huge_page_order(dst));
+		split_page_owner(folio_page(folio, 0), huge_page_order(src),
+				 huge_page_order(dst));
 		pgalloc_tag_split(folio, huge_page_order(src), huge_page_order(dst));
 
 		for (i = 0; i < pages_per_huge_page(src); i += pages_per_huge_page(dst)) {
@@ -5605,9 +5606,9 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)
 	 * be leaks between processes, for example, with FOLL_GET users.
 	 */
 	if (folio_mapcount(old_folio) == 1 && folio_test_anon(old_folio)) {
-		if (!PageAnonExclusive(&old_folio->page)) {
+		if (!PageAnonExclusive(folio_page(old_folio, 0))) {
 			folio_move_anon_rmap(old_folio, vma);
-			SetPageAnonExclusive(&old_folio->page);
+			SetPageAnonExclusive(folio_page(old_folio, 0));
 		}
 		if (likely(!unshare))
 			set_huge_ptep_maybe_writable(vma, vmf->address,
@@ -5616,8 +5617,8 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)
 		delayacct_wpcopy_end();
 		return 0;
 	}
-	VM_BUG_ON_PAGE(folio_test_anon(old_folio) &&
-		       PageAnonExclusive(&old_folio->page), &old_folio->page);
+	VM_BUG_ON_FOLIO(folio_test_anon(old_folio) &&
+			PageAnonExclusive(folio_page(old_folio, 0)), old_folio);
 
 	/*
 	 * If the process that created a MAP_PRIVATE mapping is about to perform
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index 95fd2d190f0d2..e0fdd07cc6a99 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -47,7 +47,8 @@ static phys_addr_t __init memblock_node_memory_size(int nid)
 void hugetlb_cma_free_frozen_folio(struct folio *folio)
 {
 	WARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],
-					 &folio->page, folio_nr_pages(folio)));
+					 folio_page(folio, 0),
+					 folio_nr_pages(folio)));
 }
 
 struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index 0057fa2a16a89..807c6bb23997e 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -403,7 +403,7 @@ static int __hugetlb_vmemmap_restore_folio(const struct hstate *h,
 	if (!folio_test_hugetlb_vmemmap_optimized(folio))
 		return 0;
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	vmemmap_start	+= HUGETLB_VMEMMAP_RESERVE_SIZE;
@@ -531,11 +531,11 @@ static int __hugetlb_vmemmap_optimize_folio(const struct hstate *h,
 		goto out;
 	}
 
-	copy_page(page_to_virt(vmemmap_head), folio);
+	copy_page(page_to_virt(vmemmap_head), folio_page(folio, 0));
 	list_add(&vmemmap_head->lru, vmemmap_pages);
 	memmap_pages_add(1);
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	/*
@@ -578,7 +578,7 @@ static int hugetlb_vmemmap_split_folio(const struct hstate *h, struct folio *fol
 	if (!vmemmap_should_optimize_folio(h, folio))
 		return 0;
 
-	vmemmap_start	= (unsigned long)&folio->page;
+	vmemmap_start	= (unsigned long)folio_page(folio, 0);
 	vmemmap_end	= vmemmap_start + hugetlb_vmemmap_size(h);
 
 	/*
@@ -610,7 +610,7 @@ static void __hugetlb_vmemmap_optimize_folios(struct hstate *h,
 			 * Already optimized by pre-HVO, just map the
 			 * mirrored tail page structs RO.
 			 */
-			spfn = (unsigned long)&folio->page;
+			spfn = (unsigned long)folio_page(folio, 0);
 			epfn = spfn + hugetlb_vmemmap_size(h);
 			vmemmap_wrprotect_hvo(spfn, epfn, folio_nid(folio),
 					HUGETLB_VMEMMAP_RESERVE_SIZE);
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index a11222572f978..127e5d75aa0d5 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -131,7 +131,7 @@ static int hwpoison_inject(void *data, u64 val)
 	 * the targeted owner (or on a free page).
 	 * memory_failure() will redo the check reliably inside page lock.
 	 */
-	err = hwpoison_filter(&folio->page);
+	err = hwpoison_filter(folio_page(folio, 0));
 	if (err)
 		return 0;
 
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 913086eaf17ba..63acb13f24ebd 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1793,7 +1793,7 @@ static void collect_mm_slot(struct mm_slot *slot)
 
 /* folio must be locked, and mmap_lock must be held */
 static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long addr,
-		pmd_t *pmdp, struct folio *folio, struct page *page)
+		pmd_t *pmdp, struct folio *folio)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	struct vm_fault vmf = {
@@ -1821,7 +1821,7 @@ static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long a
 	}
 
 	vmf.pmd = pmdp;
-	if (do_set_pmd(&vmf, folio, page))
+	if (do_set_pmd(&vmf, folio, folio_page(folio, 0)))
 		return SCAN_FAIL;
 
 	folio_get(folio);
@@ -2032,7 +2032,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 maybe_install_pmd:
 	/* step 5: install pmd entry */
 	result = install_pmd
-			? set_huge_pmd(vma, haddr, pmd, folio, &folio->page)
+			? set_huge_pmd(vma, haddr, pmd, folio)
 			: SCAN_SUCCEED;
 	goto drop_folio;
 abort:
diff --git a/mm/ksm.c b/mm/ksm.c
index f33523a84a1a1..bb8c564d9ffb5 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1112,7 +1112,8 @@ struct ksm_stable_node *folio_stable_node(const struct folio *folio)
 static inline void folio_set_stable_node(struct folio *folio,
 					 struct ksm_stable_node *stable_node)
 {
-	VM_WARN_ON_FOLIO(folio_test_anon(folio) && PageAnonExclusive(&folio->page), folio);
+	VM_WARN_ON_FOLIO(folio_test_anon(folio) &&
+			 PageAnonExclusive(folio_page(folio, 0)), folio);
 	WRITE_ONCE(folio->mapping,
 		   (void *)((unsigned long)stable_node | FOLIO_MAPPING_KSM));
 }
@@ -1324,7 +1325,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
 	if (unlikely(!pte_present(entry)))
 		goto out_unlock;
 
-	anon_exclusive = PageAnonExclusive(&folio->page);
+	anon_exclusive = PageAnonExclusive(folio_page(folio, 0));
 	if (pte_write(entry) || pte_dirty(entry) ||
 	    anon_exclusive || mm_tlb_flush_pending(mm)) {
 		swapped = folio_test_swapcache(folio);
@@ -1355,7 +1356,8 @@ static int write_protect_page(struct vm_area_struct *vma, struct folio *folio,
 
 		/* See folio_try_share_anon_rmap_pte(): clear PTE first. */
 		if (anon_exclusive &&
-		    folio_try_share_anon_rmap_pte(folio, &folio->page)) {
+		    folio_try_share_anon_rmap_pte(folio,
+						  folio_page(folio, 0))) {
 			set_pte_at(mm, pvmw.address, pvmw.pte, entry);
 			goto out_unlock;
 		}
@@ -1893,7 +1895,7 @@ static struct folio *stable_tree_search(struct page *page)
 			goto again;
 		}
 
-		ret = memcmp_pages(page, &tree_folio->page);
+		ret = memcmp_pages(page, folio_page(tree_folio, 0));
 		folio_put(tree_folio);
 
 		parent = *new;
@@ -2100,7 +2102,8 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
 			goto again;
 		}
 
-		ret = memcmp_pages(&kfolio->page, &tree_folio->page);
+		ret = memcmp_pages(folio_page(kfolio, 0),
+				   folio_page(tree_folio, 0));
 		folio_put(tree_folio);
 
 		parent = *new;
@@ -2333,7 +2336,8 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
 		if (kfolio == ERR_PTR(-EBUSY))
 			return;
 
-		err = try_to_merge_with_ksm_page(rmap_item, page, &kfolio->page);
+		err = try_to_merge_with_ksm_page(rmap_item, page,
+						 folio_page(kfolio, 0));
 		if (!err) {
 			/*
 			 * The page was successfully merged:
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 0c96eb5119976..771a75eb55050 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1400,7 +1400,7 @@ static int __get_hwpoison_page(struct page *page, unsigned long flags)
 	 * unsupported type of folio in order to reduce the risk of unexpected
 	 * races caused by taking a folio refcount.
 	 */
-	if (!HWPoisonHandlable(&folio->page, flags))
+	if (!HWPoisonHandlable(folio_page(folio, 0), flags))
 		return -EBUSY;
 
 	if (folio_try_get(folio)) {
@@ -1777,7 +1777,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	if (!cookie)
 		return -EBUSY;
 
-	if (hwpoison_filter(&folio->page)) {
+	if (hwpoison_filter(folio_page(folio, 0))) {
 		rc = -EOPNOTSUPP;
 		goto unlock;
 	}
@@ -1799,7 +1799,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	 * Use this flag as an indication that the dax page has been
 	 * remapped UC to prevent speculative consumption of poison.
 	 */
-	SetPageHWPoison(&folio->page);
+	folio_set_hwpoison(folio);
 
 	/*
 	 * Unlike System-RAM there is no possibility to swap in a
@@ -1808,7 +1808,7 @@ static int mf_generic_kill_procs(unsigned long long pfn, int flags,
 	 * SIGBUS (i.e. MF_MUST_KILL)
 	 */
 	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
-	collect_procs(folio, &folio->page, &to_kill, true);
+	collect_procs(folio, folio_page(folio, 0), &to_kill, true);
 
 	unmap_and_kill(&to_kill, pfn, folio->mapping, folio->index, flags);
 unlock:
diff --git a/mm/memory.c b/mm/memory.c
index 1f83a26f87333..e7c86e7301923 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1098,7 +1098,8 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
 	 * over and copy the page & arm it.
 	 */
 
-	if (copy_mc_user_highpage(&new_folio->page, page, addr, src_vma))
+	if (copy_mc_user_highpage(folio_page(new_folio, 0), page, addr,
+				  src_vma))
 		return -EHWPOISON;
 
 	*prealloc = NULL;
@@ -4035,7 +4036,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 	if (!pfn_is_zero) {
 		int err;
 
-		err = __wp_page_copy_user(&new_folio->page, vmf->page, vmf);
+		err = __wp_page_copy_user(folio_page(new_folio, 0), vmf->page,
+					  vmf);
 		if (err) {
 			/*
 			 * COW failed, if the fault was solved by other,
@@ -4051,7 +4053,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 			delayacct_wpcopy_end();
 			return err == -EHWPOISON ? VM_FAULT_HWPOISON : 0;
 		}
-		kmsan_copy_page_meta(&new_folio->page, vmf->page);
+		kmsan_copy_page_meta(folio_page(new_folio, 0), vmf->page);
 	}
 
 	__folio_mark_uptodate(new_folio);
@@ -5105,7 +5107,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
 		ptep = folio_ptep;
 		nr_pages = nr;
 		entry = folio->swap;
-		page = &folio->page;
+		page = folio_page(folio, 0);
 	}
 
 check_folio:
@@ -5659,7 +5661,7 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa
 
 	if (!is_pmd_order(folio_order(folio)))
 		return ret;
-	page = &folio->page;
+	page = folio_page(folio, 0);
 
 	/*
 	 * Just backoff if any subpage of a THP is corrupted otherwise
@@ -5870,7 +5872,7 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
 		} else {
 			/* Now we can set mappings for the whole large folio. */
 			addr = vmf->address - idx * PAGE_SIZE;
-			page = &folio->page;
+			page = folio_page(folio, 0);
 		}
 	}
 
@@ -6055,7 +6057,7 @@ static vm_fault_t do_cow_fault(struct vm_fault *vmf)
 	if (!folio)
 		return VM_FAULT_OOM;
 
-	vmf->cow_page = &folio->page;
+	vmf->cow_page = folio_page(folio, 0);
 
 	ret = __do_fault(vmf);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 796af1028ee23..47bf3b5d3ff27 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1952,7 +1952,7 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 				if (__ratelimit(&migrate_rs)) {
 					pr_warn("migrating pfn %lx failed ret:%d\n",
 						folio_pfn(folio), ret);
-					dump_page(&folio->page,
+					dump_page(folio_page(folio, 0),
 						  "migration failure");
 				}
 			}
diff --git a/mm/memremap.c b/mm/memremap.c
index accba23aef28c..70cfd3f05a257 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -467,7 +467,7 @@ void free_zone_device_folio(struct folio *folio)
 		break;
 
 	case MEMORY_DEVICE_FS_DAX:
-		wake_up_var(&folio->page);
+		wake_up_var(folio_page(folio, 0));
 		break;
 
 	case MEMORY_DEVICE_PCI_P2PDMA:
diff --git a/mm/migrate.c b/mm/migrate.c
index 7bdcdb57652f8..b027c938d8301 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -266,8 +266,8 @@ void putback_movable_pages(struct list_head *l)
 			continue;
 		}
 		list_del(&folio->lru);
-		if (unlikely(page_has_movable_ops(&folio->page))) {
-			putback_movable_ops_page(&folio->page);
+		if (unlikely(page_has_movable_ops(folio_page(folio, 0)))) {
+			putback_movable_ops_page(folio_page(folio, 0));
 		} else {
 			node_stat_mod_folio(folio, NR_ISOLATED_ANON +
 					folio_is_file_lru(folio), -folio_nr_pages(folio));
@@ -282,8 +282,8 @@ bool isolate_folio_to_list(struct folio *folio, struct list_head *list)
 	if (folio_test_hugetlb(folio))
 		return folio_isolate_hugetlb(folio, list);
 
-	if (page_has_movable_ops(&folio->page)) {
-		if (!isolate_movable_ops_page(&folio->page,
+	if (page_has_movable_ops(folio_page(folio, 0))) {
+		if (!isolate_movable_ops_page(folio_page(folio, 0),
 					      ISOLATE_UNEVICTABLE))
 			return false;
 	} else {
@@ -1199,7 +1199,8 @@ static void migrate_folio_undo_dst(struct folio *dst, bool locked,
 static void migrate_folio_done(struct folio *src,
 			       enum migrate_reason reason)
 {
-	if (likely(!page_has_movable_ops(&src->page)) && reason != MR_DEMOTION)
+	if (likely(!page_has_movable_ops(folio_page(src, 0))) &&
+	    reason != MR_DEMOTION)
 		mod_node_page_state(folio_pgdat(src), NR_ISOLATED_ANON +
 				    folio_is_file_lru(src), -folio_nr_pages(src));
 
@@ -1308,7 +1309,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
 		goto out;
 	dst_locked = true;
 
-	if (unlikely(page_has_movable_ops(&src->page))) {
+	if (unlikely(page_has_movable_ops(folio_page(src, 0)))) {
 		__migrate_folio_record(dst, old_folio_state, anon_vma);
 		return 0;
 	}
@@ -1375,8 +1376,9 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
 	prev = dst->lru.prev;
 	list_del(&dst->lru);
 
-	if (unlikely(page_has_movable_ops(&src->page))) {
-		rc = migrate_movable_ops_page(&dst->page, &src->page, mode);
+	if (unlikely(page_has_movable_ops(folio_page(src, 0)))) {
+		rc = migrate_movable_ops_page(folio_page(dst, 0),
+					      folio_page(src, 0), mode);
 		if (rc)
 			goto out;
 		goto out_unlock_both;
@@ -1903,7 +1905,7 @@ static int migrate_pages_batch(struct list_head *from,
 			 * If we are holding the last folio reference, the folio
 			 * was freed from under us, so just drop our reference.
 			 */
-			if (likely(!page_has_movable_ops(&folio->page)) &&
+			if (likely(!page_has_movable_ops(folio_page(folio, 0))) &&
 			    folio_ref_count(folio) == 1) {
 				folio_clear_active(folio);
 				folio_clear_unevictable(folio);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 641384085e341..870ff378d61d2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3006,17 +3006,18 @@ void free_unref_folios(struct folio_batch *folios)
 	/* Prepare folios for freeing */
 	for (i = 0, j = 0; i < folios->nr; i++) {
 		struct folio *folio = folios->folios[i];
+		struct page *page = folio_page(folio, 0);
 		unsigned long pfn = folio_pfn(folio);
 		unsigned int order = folio_order(folio);
 
-		if (!__free_pages_prepare(&folio->page, order, FPI_NONE))
+		if (!__free_pages_prepare(page, order, FPI_NONE))
 			continue;
 		/*
 		 * Free orders not handled on the PCP directly to the
 		 * allocator.
 		 */
 		if (!pcp_allowed_order(order)) {
-			free_one_page(folio_zone(folio), &folio->page,
+			free_one_page(folio_zone(folio), page,
 				      pfn, order, FPI_NONE);
 			continue;
 		}
@@ -3029,13 +3030,14 @@ void free_unref_folios(struct folio_batch *folios)
 
 	for (i = 0; i < folios->nr; i++) {
 		struct folio *folio = folios->folios[i];
+		struct page *page = folio_page(folio, 0);
 		struct zone *zone = folio_zone(folio);
 		unsigned long pfn = folio_pfn(folio);
 		unsigned int order = (unsigned long)folio->private;
 		int migratetype;
 
 		folio->private = NULL;
-		migratetype = get_pfnblock_migratetype(&folio->page, pfn);
+		migratetype = get_pfnblock_migratetype(page, pfn);
 
 		/* Different zone requires a different pcp lock */
 		if (zone != locked_zone ||
@@ -3051,7 +3053,7 @@ void free_unref_folios(struct folio_batch *folios)
 			 * allocator, see comment in free_frozen_pages.
 			 */
 			if (is_migrate_isolate(migratetype)) {
-				free_one_page(zone, &folio->page, pfn,
+				free_one_page(zone, page, pfn,
 					      order, FPI_NONE);
 				continue;
 			}
@@ -3062,7 +3064,7 @@ void free_unref_folios(struct folio_batch *folios)
 			 */
 			pcp = pcp_spin_trylock(zone->per_cpu_pageset);
 			if (unlikely(!pcp)) {
-				free_one_page(zone, &folio->page, pfn,
+				free_one_page(zone, page, pfn,
 					      order, FPI_NONE);
 				continue;
 			}
@@ -3076,9 +3078,9 @@ void free_unref_folios(struct folio_batch *folios)
 		if (unlikely(migratetype >= MIGRATE_PCPTYPES))
 			migratetype = MIGRATE_MOVABLE;
 
-		trace_mm_page_free_batched(&folio->page);
-		if (!free_frozen_page_commit(zone, pcp, &folio->page,
-				migratetype, order, FPI_NONE)) {
+		trace_mm_page_free_batched(page);
+		if (!free_frozen_page_commit(zone, pcp, page,
+					     migratetype, order, FPI_NONE)) {
 			pcp = NULL;
 			locked_zone = NULL;
 		}
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 5aaad037384e4..29c9e108b2e59 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -47,7 +47,7 @@ bool page_is_unmovable(struct zone *zone, struct page *page,
 		unsigned long nr_pages, pfn;
 		unsigned int order;
 
-		order = compound_order(&folio->page);
+		order = compound_order(folio_page(folio, 0));
 		if (order > MAX_FOLIO_ORDER)
 			return true;
 
diff --git a/mm/page_owner.c b/mm/page_owner.c
index cfc31c92d7657..39c381699a633 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -365,7 +365,7 @@ noinline void __set_page_owner(struct page *page, unsigned short order,
 
 void __folio_set_owner_migrate_reason(struct folio *folio, enum migrate_reason reason)
 {
-	struct page_ext *page_ext = page_ext_get(&folio->page);
+	struct page_ext *page_ext = page_ext_get(folio_page(folio, 0));
 	struct page_owner *page_owner;
 
 	if (unlikely(!page_ext))
@@ -398,14 +398,14 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	struct page_owner *new_page_owner;
 	depot_stack_handle_t migrate_handle;
 
-	page_ext = page_ext_get(&old->page);
+	page_ext = page_ext_get(folio_page(old, 0));
 	if (unlikely(!page_ext))
 		return;
 
 	old_page_owner = get_page_owner(page_ext);
 	page_ext_put(page_ext);
 
-	page_ext = page_ext_get(&newfolio->page);
+	page_ext = page_ext_get(folio_page(newfolio, 0));
 	if (unlikely(!page_ext))
 		return;
 
@@ -413,7 +413,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	page_ext_put(page_ext);
 
 	migrate_handle = new_page_owner->handle;
-	__update_page_owner_handle(&newfolio->page, old_page_owner->handle,
+	__update_page_owner_handle(folio_page(newfolio, 0),
+				   old_page_owner->handle,
 				   old_page_owner->order, old_page_owner->gfp_mask,
 				   old_page_owner->last_migrate_reason,
 				   old_page_owner->ts_nsec, old_page_owner->pid,
@@ -423,7 +424,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	 * will be freed after migration. Keep them until then as they may be
 	 * useful.
 	 */
-	__update_page_owner_free_handle(&newfolio->page, 0, old_page_owner->order,
+	__update_page_owner_free_handle(folio_page(newfolio, 0), 0,
+					old_page_owner->order,
 					old_page_owner->free_pid,
 					old_page_owner->free_tgid,
 					old_page_owner->free_ts_nsec);
@@ -433,7 +435,8 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
 	 * when subtracting those pages from the stack.
 	 */
 	rcu_read_lock();
-	for_each_page_ext(&old->page, 1 << new_page_owner->order, page_ext, iter) {
+	for_each_page_ext(folio_page(old, 0), 1 << new_page_owner->order,
+			  page_ext, iter) {
 		old_page_owner = get_page_owner(page_ext);
 		old_page_owner->handle = migrate_handle;
 	}
diff --git a/mm/rmap.c b/mm/rmap.c
index fbd66a2823b7b..cd1cf570c770d 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1668,7 +1668,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 		/* increment count (starts at -1) */
 		atomic_set(&folio->_mapcount, 0);
 		if (exclusive)
-			SetPageAnonExclusive(&folio->page);
+			SetPageAnonExclusive(folio_page(folio, 0));
 	} else if (!folio_test_pmd_mappable(folio)) {
 		int i;
 
@@ -1694,7 +1694,7 @@ void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 		if (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))
 			atomic_set(&folio->_nr_pages_mapped, ENTIRELY_MAPPED);
 		if (exclusive)
-			SetPageAnonExclusive(&folio->page);
+			SetPageAnonExclusive(folio_page(folio, 0));
 		nr_pmdmapped = nr;
 	}
 
@@ -3187,9 +3187,9 @@ void hugetlb_add_anon_rmap(struct folio *folio, struct vm_area_struct *vma,
 	atomic_inc(&folio->_entire_mapcount);
 	atomic_inc(&folio->_large_mapcount);
 	if (flags & RMAP_EXCLUSIVE)
-		SetPageAnonExclusive(&folio->page);
+		SetPageAnonExclusive(folio_page(folio, 0));
 	VM_WARN_ON_FOLIO(folio_entire_mapcount(folio) > 1 &&
-			 PageAnonExclusive(&folio->page), folio);
+			 PageAnonExclusive(folio_page(folio, 0)), folio);
 }
 
 void hugetlb_add_new_anon_rmap(struct folio *folio,
@@ -3203,6 +3203,6 @@ void hugetlb_add_new_anon_rmap(struct folio *folio,
 	atomic_set(&folio->_large_mapcount, 0);
 	folio_clear_hugetlb_restore_reserve(folio);
 	__folio_set_anon(folio, vma, address, true);
-	SetPageAnonExclusive(&folio->page);
+	SetPageAnonExclusive(folio_page(folio, 0));
 }
 #endif /* CONFIG_HUGETLB_PAGE */
diff --git a/mm/shmem.c b/mm/shmem.c
index ae08cff4500c3..940af0067ddf4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -6192,7 +6192,7 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
 	struct page *page;
 
 	if (IS_ERR(folio))
-		return &folio->page;
+		return ERR_CAST(folio);
 
 	page = folio_file_page(folio, index);
 	if (PageHWPoison(page)) {
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 3c7fd39deb137..a39d7d40a76b0 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -565,7 +565,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,
 				goto err_folio_put;
 		}
 	} else if (uffd_flags_mode_is(flags, MFILL_ATOMIC_ZEROPAGE)) {
-		clear_user_highpage(&folio->page, state->dst_addr);
+		clear_user_highpage(folio_page(folio, 0), state->dst_addr);
 	} else {
 		VM_WARN_ONCE(1, "Unknown UFFDIO operation, flags: %x", flags);
 	}
@@ -584,7 +584,7 @@ static int __mfill_atomic_pte(struct mfill_state *state,
 	}
 
 	ret = mfill_atomic_install_pte(state->pmd, state->vma, dst_addr,
-				       &folio->page, flags);
+				       folio_page(folio, 0), flags);
 	if (ret)
 		goto err_filemap_remove;
 
@@ -1268,7 +1268,8 @@ static struct folio *check_ptes_for_batched_move(struct vm_area_struct *src_vma,
 	folio = vm_normal_folio(src_vma, src_addr, orig_src_pte);
 	if (!folio || !folio_trylock(folio))
 		return NULL;
-	if (!PageAnonExclusive(&folio->page) || folio_test_large(folio)) {
+	if (!PageAnonExclusive(folio_page(folio, 0)) ||
+	    folio_test_large(folio)) {
 		folio_unlock(folio);
 		return NULL;
 	}
@@ -1306,7 +1307,7 @@ static long move_present_ptes(struct mm_struct *mm,
 	}
 	if (folio_test_large(src_folio) ||
 	    folio_maybe_dma_pinned(src_folio) ||
-	    !PageAnonExclusive(&src_folio->page)) {
+	    !PageAnonExclusive(folio_page(src_folio, 0))) {
 		err = -EBUSY;
 		goto out;
 	}
@@ -1590,7 +1591,8 @@ static long move_pages_ptes(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd
 			}
 
 			folio = vm_normal_folio(src_vma, src_addr, orig_src_pte);
-			if (!folio || !PageAnonExclusive(&folio->page)) {
+			if (!folio ||
+			    !PageAnonExclusive(folio_page(folio, 0))) {
 				spin_unlock(src_ptl);
 				ret = -EBUSY;
 				goto out;
@@ -2072,7 +2074,7 @@ static ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
 					struct folio *folio = pmd_folio(*src_pmd);
 
 					if (!is_huge_zero_folio(folio) &&
-					    !PageAnonExclusive(&folio->page)) {
+					    !PageAnonExclusive(folio_page(folio, 0))) {
 						spin_unlock(ptl);
 						err = -EBUSY;
 						break;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 91295070ca336..150ffeec3d478 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1709,7 +1709,7 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone,
 
 	list_for_each_entry_safe(folio, next, folio_list, lru) {
 		/* TODO: these pages should not even appear in this list. */
-		if (page_has_movable_ops(&folio->page))
+		if (page_has_movable_ops(folio_page(folio, 0)))
 			continue;
 		if (!folio_test_hugetlb(folio) && folio_is_file_lru(folio) &&
 		    !folio_test_dirty(folio) && !folio_test_unevictable(folio)) {

49/3 2026/09/30 22:03 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 18340
							output: 19
							thoughts: 1042
						

Thoughts:
**KMSAN Fuzzing Session Justification**

Okay, let's see if this patch series warrants a dedicated KMSAN fuzzing session. My initial thought is to analyze the scope of the change. It looks like it touches a significant swathe of the memory management subsystem: `mm/alloc_tag.c`, `mm/compaction.c`, `mm/filemap.c`, `mm/folio.c`, `mm/gup.c`, and so on, all the way down to `mm/vmscan.c`. That's a lot of files to touch, which piques my interest.

The core of the patch seems to revolve around replacing direct references to `&folio->page` with `folio_page(folio, 0)`. The most intriguing part is when `&folio->page` is used in a return statement, as in the cases where the folio is an error pointer. It seems to be fixing a bug where taking the address offset an ERR_PTR or similar! That's a red flag – potential undefined behavior and use-after-free scenarios if things aren't handled correctly. The fact that the code was returning the address of a member of a potentially invalid structure suggests a deep change in the memory model.

Digging deeper, I suspect this is related to Matthew Wilcox's folio unification/decoupling project. The definition of `struct folio` is either changing to decouple it from the underlying `struct page`, or it is already decoupled. The replacement with `folio_page(folio, 0)` is consistent with this. This function must be providing a safe way to access the `struct page` associated with the folio, regardless of the folio's internal structure or offset.

Looking at examples like `do_read_cache_page` and `compaction.c`, the patch is changing how `struct page` is accessed. For instance, `&folio->page` is replaced with `folio_page(folio, 0)`, which means that the code was likely relying on `offsetof(struct folio, page) == 0`. It's a subtle but significant change, and relying on `offsetof` can easily break with even a small change to the structure. The removal of the direct reference to `dst->page` and its replacement with `freepage` in `compaction_alloc_noprof` and `compaction_free` suggests a possible abstraction of the page or folio structure, which is important to protect against potential misuses.

Also the KMSAN is copied over to folio through a call to `kmsan_copy_page_meta`, but now it seems to be using `folio_page(new_folio, 0)` in `mm/memory.c`.

To confirm the change and the function's safety, I need to check what `folio_page(folio, 0)` is defined as. I'm going to run grepper to find that definition. Depending on the definition, this could be a big deal in terms of where and how we allocate memory.



50/3 2026/09/30 22:03 tool grepper
0m Args:
{
  "Expression": "#define folio_page"
}

Results:
{
  "Output": "include/linux/page-flags.h=277=static __always_inline void clear_compound_head(struct page *page)\n--\ninclude/linux/page-flags.h-307- */\ninclude/linux/page-flags.h:308:#define folio_page(folio, n)\t(\u0026(folio)-\u003epage + (n))\ninclude/linux/page-flags.h-309-\n"
}

51/3 2026/09/30 22:03 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 20151
							output: 247
							thoughts: 2048
						

Thoughts:
**KMSAN Assessment: Refactoring `folio->page` Access**

Okay, so this patch is essentially a widespread cleanup in the memory management subsystem. The primary change is the replacement of direct member access, `&folio->page`, with the helper function/macro `folio_page(folio, 0)`. The aim is to improve consistency, abstraction, and prepare for future modifications to the `struct folio` definition. There are also a few instances where `ERR_PTR` usage is cleaned up with `ERR_CAST`.

My initial thought was to ensure this patch doesn't inadvertently introduce any potential for uninitialized memory usage, which is, after all, what KMSAN is all about. The KMSAN rules are very clear: we need to be concerned if the patch introduces or modifies kernel structures sent to userspace, conditional logic that depends on uninitialized variables, or the allocation/initialization of complex data structures where uninitialized fields could be read later.

Let's break this down further and systematically look at the changes:

1.  `mm/alloc_tag.c`, `mm/gup.c`, `mm/gup_test.c`, `mm/huge_memory.c`, `mm/hugetlb.c`, `mm/hugetlb_cma.c`, `mm/hugetlb_vmemmap.c`, `mm/hwpoison-inject.c`, `mm/ksm.c`, `mm/memory-failure.c`, `mm/memory.c`, `mm/memory_hotplug.c`, `mm/memremap.c`, `mm/migrate.c`, `mm/page_alloc.c`, `mm/page_isolation.c`, `mm/page_owner.c`, `mm/rmap.c`, `mm/shmem.c`, `mm/userfaultfd.c`, `mm/vmscan.c`: These are pure substitutions. The core change here is simply replacing `&folio->page` with the equivalent `folio_page(folio, 0)`. There's no change in the underlying data access or initialization. It's just a refactoring. The same applies to the error pointer casting cleanup.

2.  `mm/compaction.c`: This is a bit more involved, but after reviewing, the change is just in how `freepage` (which is a `struct page *`) is used. There's no change in the initialization or copying of any page data. The `folio` dereference is a conversion and direct access to a folio member. The same goes for the other case, where a `struct folio *` is converted to a `struct page *`.

3.  `mm/filemap.c`: With the `do_read_cache_page` changes, the use of `ERR_CAST` is *correct*, as `&folio->page` would be incorrect when `folio` is an error pointer. It isn't introducing uninitialized memory. It's properly handling an error case.

In essence, these changes are all about *how* we access the page structure within a folio, and they *do not* change *what* is being accessed or how it's initialized. There is a lot of code, but the function of it doesn't change from `(&folio->page + 0)`.

Here's my assessment:

*   The patch's *purpose* is code cleanup, replacing direct access with a standard helper, and ensuring correct error handling.
*   KMSAN is concerned with *uninitialized* memory reads or leaks.
*   This patch does *not* introduce new memory allocations, alter data buffer initialization, change the scope of variables, or introduce struct fields that could be uninitialized.
*   No data copied to userspace is affected, and nothing is exposed without explicit initialization.
*   The `&folio->page` to `folio_page(folio, 0)` replacement is, at the machine level, functionally identical.
*   Any issues that *could* arise from this refactoring (e.g., pointer type mismatches or incorrect page references) would manifest as memory corruption, page flag errors, or reference count problems. These are precisely the kinds of bugs KASAN, VM assertions (CONFIG\_DEBUG\_VM), and standard testing are designed to catch. KMSAN isn't the right tool here.

Therefore, `NeedsKMSAN = false`.



52/3 2026/09/30 22:03 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch series performs a mechanical refactoring across the core memory management subsystem (alloc_tag, compaction, filemap, gup, huge_memory, hugetlb, ksm, memory, migrate, page_alloc, rmap, etc.) replacing direct accesses to '\u0026folio-\u003epage' with the helper 'folio_page(folio, 0)', and replacing '\u0026folio-\u003epage' error returns with 'ERR_CAST(folio)'.\n\nAt the machine level, 'folio_page(folio, 0)' expands to '(\u0026(folio)-\u003epage + 0)', which is functionally and semantically identical to '\u0026folio-\u003epage'. The patch does not introduce new allocations, alter struct initialization or layout, modify memory copies to user space, or affect control flow based on uninitialized data. There are no risks of uninitialized memory access or kernel-to-user info-leaks. Any potential regression from page pointer manipulation would be caught by CONFIG_DEBUG_VM assertions, KASAN, or standard kernel debug facilities. A dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch series performs a mechanical refactoring across the core memory management subsystem (alloc_tag, compaction, filemap, gup, huge_memory, hugetlb, ksm, memory, migrate, page_alloc, rmap, etc.) replacing direct accesses to '\u0026folio-\u003epage' with the helper 'folio_page(folio, 0)', and replacing '\u0026folio-\u003epage' error returns with 'ERR_CAST(folio)'.\n\nAt the machine level, 'folio_page(folio, 0)' expands to '(\u0026(folio)-\u003epage + 0)', which is functionally and semantically identical to '\u0026folio-\u003epage'. The patch does not introduce new allocations, alter struct initialization or layout, modify memory copies to user space, or affect control flow based on uninitialized data. There are no risks of uninitialized memory access or kernel-to-user info-leaks. Any potential regression from page pointer manipulation would be caught by CONFIG_DEBUG_VM assertions, KASAN, or standard kernel debug facilities. A dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)