AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/07 20:37 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "HUGETLBFS",
    "SWAP",
    "MEMORY_FAILURE",
    "HWPOISON_INJECT"
  ],
  "FocusSymbols": [
    "try_to_unmap_hugetlb_one",
    "ttu_anon_folio",
    "ttu_anon_lazyfree_folio",
    "ttu_anon_swapbacked_folio",
    "try_to_unmap_one"
  ],
  "Reasoning": "The patch refactors the unmapping logic in mm/rmap.c by extracting hugetlb and anonymous folio unmapping into separate functions (try_to_unmap_hugetlb_one, ttu_anon_folio, etc.). It modifies core memory management logic related to reverse mapping, huge pages, and swap. Fuzzing should focus on these new functions to ensure no regressions or bugs were introduced during the refactoring.",
  "WorthFuzzing": true
}

1/1 2026/07/07 20:37 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 1e84bc0e0c206f915008ad4c71905ceb278b1c58\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Jul 7 20:37:44 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h\nindex 4115076e4922ae..bf7e163e3779d8 100644\n--- a/include/linux/hugetlb.h\n+++ b/include/linux/hugetlb.h\n@@ -1271,6 +1271,7 @@ static inline void hugetlb_count_sub(long l, struct mm_struct *mm)\n }\n \n pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);\n+unsigned long huge_pte_dirty(pte_t pte);\n \n static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,\n \t\t\t\t\t  unsigned long addr, pte_t *ptep)\ndiff --git a/mm/rmap.c b/mm/rmap.c\nindex 9939400e77c79a..f021ecd51a4a2e 100644\n--- a/mm/rmap.c\n+++ b/mm/rmap.c\n@@ -1978,6 +1978,233 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,\n \t\t\t\t     FPB_RESPECT_WRITE | FPB_RESPECT_SOFT_DIRTY);\n }\n \n+static bool try_to_unmap_hugetlb_one(struct folio *folio,\n+\t\tstruct vm_area_struct *vma, unsigned long address, void *arg)\n+{\n+\tDEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);\n+\tstruct mmu_notifier_range range;\n+\tenum ttu_flags flags = (enum ttu_flags)(long)arg;\n+\tstruct mm_struct *mm = vma-\u003evm_mm;\n+\tconst unsigned long hsz = huge_page_size(hstate_vma(vma));\n+\tbool ret = true;\n+\tpte_t pteval;\n+\n+\t/*\n+\t * The try_to_unmap() is only passed a hugetlb folio in the case\n+\t * where the hugetlb folio is poisoned.\n+\t */\n+\tVM_WARN_ON_FOLIO(!folio_test_hwpoison(folio), folio);\n+\tVM_WARN_ON_ONCE(!(flags \u0026 TTU_HWPOISON));\n+\n+\trange.end = vma_address_end(\u0026pvmw);\n+\tmmu_notifier_range_init(\u0026range, MMU_NOTIFY_CLEAR, 0, vma-\u003evm_mm,\n+\t\t\t\taddress, range.end);\n+\tadjust_range_if_pmd_sharing_possible(vma, \u0026range.start, \u0026range.end);\n+\tmmu_notifier_invalidate_range_start(\u0026range);\n+\n+\t/* There is only a single mapping in a VMA. */\n+\tif (!page_vma_mapped_walk(\u0026pvmw))\n+\t\tgoto range_end;\n+\n+\taddress = pvmw.address;\n+\tpteval = huge_ptep_get(mm, address, pvmw.pte);\n+\tVM_WARN_ON_ONCE(!pte_present(pteval));\n+\tVM_WARN_ON_ONCE(pte_pfn(pteval) != folio_pfn(folio));\n+\n+\t/*\n+\t * huge_pmd_unshare may unmap an entire PMD page. There is no way of\n+\t * knowing exactly which PMDs may be cached for this mm, so we must\n+\t * flush them all. start/end were already adjusted above to cover this\n+\t * range.\n+\t */\n+\tflush_cache_range(vma, range.start, range.end);\n+\n+\t/*\n+\t * To call huge_pmd_unshare, i_mmap_rwsem must be held in write mode.\n+\t * Caller needs to explicitly do this outside rmap routines.\n+\t *\n+\t * We also must hold hugetlb vma_lock in write mode. Lock order dictates\n+\t * acquiring vma_lock BEFORE i_mmap_rwsem. We can only try lock here and\n+\t * fail if unsuccessful.\n+\t */\n+\tif (!folio_test_anon(folio)) {\n+\t\tstruct mmu_gather tlb;\n+\n+\t\tVM_WARN_ON(!(flags \u0026 TTU_RMAP_LOCKED));\n+\t\tif (!hugetlb_vma_trylock_write(vma)) {\n+\t\t\tret = false;\n+\t\t\tgoto walk_done;\n+\t\t}\n+\n+\t\ttlb_gather_mmu_vma(\u0026tlb, vma);\n+\t\tif (huge_pmd_unshare(\u0026tlb, vma, address, pvmw.pte)) {\n+\t\t\thugetlb_vma_unlock_write(vma);\n+\t\t\thuge_pmd_unshare_flush(\u0026tlb, vma);\n+\t\t\ttlb_finish_mmu(\u0026tlb);\n+\t\t\t/*\n+\t\t\t * The PMD table was unmapped, consequently unmapping\n+\t\t\t * the folio.\n+\t\t\t */\n+\t\t\tgoto walk_done;\n+\t\t}\n+\t\thugetlb_vma_unlock_write(vma);\n+\t\ttlb_finish_mmu(\u0026tlb);\n+\t}\n+\tpteval = huge_ptep_clear_flush(vma, address, pvmw.pte);\n+\tif (huge_pte_dirty(pteval))\n+\t\tfolio_mark_dirty(folio);\n+\n+\tpteval = swp_entry_to_pte(make_hwpoison_entry(folio_page(folio, 0)));\n+\thugetlb_count_sub(folio_nr_pages(folio), mm);\n+\tset_huge_pte_at(mm, address, pvmw.pte, pteval, hsz);\n+\thugetlb_remove_rmap(folio);\n+\tfolio_put_refs(folio, 1);\n+\n+walk_done:\n+\tpage_vma_mapped_walk_done(\u0026pvmw);\n+range_end:\n+\tmmu_notifier_invalidate_range_end(\u0026range);\n+\treturn ret;\n+}\n+\n+static inline bool ttu_anon_lazyfree_folio(struct vm_area_struct *vma,\n+\t\tstruct folio *folio)\n+{\n+\tint ref_count, map_count;\n+\n+\t/*\n+\t * Synchronize with gup_pte_range():\n+\t * - clear PTE; barrier; read refcount\n+\t * - inc refcount; barrier; read PTE\n+\t */\n+\tsmp_mb();\n+\n+\tref_count = folio_ref_count(folio);\n+\tmap_count = folio_mapcount(folio);\n+\n+\t/*\n+\t * Order reads for page refcount and dirty flag\n+\t * (see comments in __remove_mapping()).\n+\t */\n+\tsmp_rmb();\n+\n+\tif (folio_test_dirty(folio) \u0026\u0026 !(vma-\u003evm_flags \u0026 VM_DROPPABLE)) {\n+\t\t/*\n+\t\t * redirtied either using the page table or a previously\n+\t\t * obtained GUP reference.\n+\t\t */\n+\t\tfolio_set_swapbacked(folio);\n+\t\treturn false;\n+\t}\n+\n+\tif (ref_count != 1 + map_count) {\n+\t\t/*\n+\t\t * Additional reference. Could be a GUP reference or any\n+\t\t * speculative reference. GUP users must mark the folio\n+\t\t * dirty if there was a modification. This folio cannot be\n+\t\t * reclaimed right now either way, so act just like nothing\n+\t\t * happened.\n+\t\t * We'll come back here later and detect if the folio was\n+\t\t * dirtied when the additional reference is gone.\n+\t\t */\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+static inline void set_swp_pte_at(struct mm_struct *mm, unsigned long address,\n+\t\tpte_t *ptep, swp_entry_t entry, pte_t pteval, bool anon_exclusive)\n+{\n+\tpte_t swp_pte = swp_entry_to_pte(entry);\n+\n+\tif (anon_exclusive)\n+\t\tswp_pte = pte_swp_mkexclusive(swp_pte);\n+\n+\tif (likely(pte_present(pteval))) {\n+\t\tif (pte_soft_dirty(pteval))\n+\t\t\tswp_pte = pte_swp_mksoft_dirty(swp_pte);\n+\t\tif (pte_uffd_wp(pteval))\n+\t\t\tswp_pte = pte_swp_mkuffd_wp(swp_pte);\n+\t} else {\n+\t\t/* Device-exclusive entry */\n+\t\tif (pte_swp_soft_dirty(pteval))\n+\t\t\tswp_pte = pte_swp_mksoft_dirty(swp_pte);\n+\t\tif (pte_swp_uffd_wp(pteval))\n+\t\t\tswp_pte = pte_swp_mkuffd_wp(swp_pte);\n+\t}\n+\n+\tset_pte_at(mm, address, ptep, swp_pte);\n+}\n+\n+static inline bool ttu_anon_swapbacked_folio(struct vm_area_struct *vma, struct folio *folio,\n+\t\tstruct page *subpage, unsigned long address, pte_t *ptep,\n+\t\tpte_t pteval)\n+{\n+\tbool anon_exclusive = folio_test_anon(folio) \u0026\u0026 PageAnonExclusive(subpage);\n+\tswp_entry_t entry = page_swap_entry(subpage);\n+\tstruct mm_struct *mm = vma-\u003evm_mm;\n+\n+\tif (folio_dup_swap(folio, subpage) \u003c 0)\n+\t\treturn false;\n+\n+\t/*\n+\t * arch_unmap_one() is expected to be a NOP on\n+\t * architectures where we could have PFN swap PTEs,\n+\t * so we'll not check/care.\n+\t */\n+\tif (arch_unmap_one(mm, vma, address, pteval) \u003c 0) {\n+\t\tfolio_put_swap(folio, subpage);\n+\t\treturn false;\n+\t}\n+\n+\t/* See folio_try_share_anon_rmap(): clear PTE first. */\n+\tif (anon_exclusive \u0026\u0026 folio_try_share_anon_rmap_pte(folio, subpage)) {\n+\t\tfolio_put_swap(folio, subpage);\n+\t\treturn false;\n+\t}\n+\n+\tmm_prepare_for_swap_entries(mm);\n+\tdec_mm_counter(mm, MM_ANONPAGES);\n+\tinc_mm_counter(mm, MM_SWAPENTS);\n+\tset_swp_pte_at(mm, address, ptep, entry, pteval, anon_exclusive);\n+\treturn true;\n+}\n+\n+static inline bool ttu_anon_folio(struct vm_area_struct *vma, struct folio *folio,\n+\t\tstruct page *subpage, unsigned long address, pte_t *ptep,\n+\t\tpte_t pteval, unsigned long nr_pages)\n+{\n+\tstruct mm_struct *mm = vma-\u003evm_mm;\n+\tbool ret;\n+\n+\t/*\n+\t * Store the swap location in the pte.\n+\t * See handle_pte_fault() ...\n+\t */\n+\tif (unlikely(folio_test_swapbacked(folio) !=\n+\t\t\tfolio_test_swapcache(folio))) {\n+\t\tWARN_ON_ONCE(1);\n+\t\treturn false;\n+\t}\n+\n+\t/* MADV_FREE page check */\n+\tif (!folio_test_swapbacked(folio)) {\n+\t\tret = ttu_anon_lazyfree_folio(vma, folio);\n+\t\tif (ret)\n+\t\t\tadd_mm_counter(mm, MM_ANONPAGES, -nr_pages);\n+\t} else {\n+\t\t/* nr_pages \u003e 1 not supported yet */\n+\t\tret = ttu_anon_swapbacked_folio(vma, folio, subpage, address,\n+\t\t\t\t\t\tptep, pteval);\n+\t}\n+\n+\tif (!ret)\n+\t\tset_ptes(mm, address, ptep, pteval, nr_pages);\n+\n+\treturn ret;\n+}\n+\n /*\n  * @arg: enum ttu_flags will be passed to this argument\n  */\n@@ -1986,14 +2213,13 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n {\n \tstruct mm_struct *mm = vma-\u003evm_mm;\n \tDEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);\n-\tbool anon_exclusive, ret = true;\n+\tbool ret = true;\n \tpte_t pteval;\n \tstruct page *subpage;\n \tstruct mmu_notifier_range range;\n \tenum ttu_flags flags = (enum ttu_flags)(long)arg;\n \tunsigned long nr_pages = 1, end_addr;\n \tunsigned long pfn;\n-\tunsigned long hsz = 0;\n \tint ptes = 0;\n \n \t/*\n@@ -2007,8 +2233,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \n \t/*\n \t * For THP, we have to assume the worse case ie pmd for invalidation.\n-\t * For hugetlb, it could be much worse if we need to do pud\n-\t * invalidation in the case of pmd sharing.\n \t *\n \t * Note that the folio can not be freed in this function as call of\n \t * try_to_unmap() must hold a reference on the folio.\n@@ -2016,17 +2240,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \trange.end = vma_address_end(\u0026pvmw);\n \tmmu_notifier_range_init(\u0026range, MMU_NOTIFY_CLEAR, 0, vma-\u003evm_mm,\n \t\t\t\taddress, range.end);\n-\tif (folio_test_hugetlb(folio)) {\n-\t\t/*\n-\t\t * If sharing is possible, start and end will be adjusted\n-\t\t * accordingly.\n-\t\t */\n-\t\tadjust_range_if_pmd_sharing_possible(vma, \u0026range.start,\n-\t\t\t\t\t\t     \u0026range.end);\n-\n-\t\t/* We need the huge page size for set_huge_pte_at() */\n-\t\thsz = huge_page_size(hstate_vma(vma));\n-\t}\n \tmmu_notifier_invalidate_range_start(\u0026range);\n \n \twhile (page_vma_mapped_walk(\u0026pvmw)) {\n@@ -2111,65 +2324,11 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\tconst softleaf_t entry = softleaf_from_pte(pteval);\n \n \t\t\tpfn = softleaf_to_pfn(entry);\n-\t\t\tVM_WARN_ON_FOLIO(folio_test_hugetlb(folio), folio);\n \t\t}\n \n \t\tsubpage = folio_page(folio, pfn - folio_pfn(folio));\n-\t\tanon_exclusive = folio_test_anon(folio) \u0026\u0026\n-\t\t\t\t PageAnonExclusive(subpage);\n \n-\t\tif (folio_test_hugetlb(folio)) {\n-\t\t\tbool anon = folio_test_anon(folio);\n-\n-\t\t\t/*\n-\t\t\t * The try_to_unmap() is only passed a hugetlb page\n-\t\t\t * in the case where the hugetlb page is poisoned.\n-\t\t\t */\n-\t\t\tVM_BUG_ON_PAGE(!PageHWPoison(subpage), subpage);\n-\t\t\t/*\n-\t\t\t * huge_pmd_unshare may unmap an entire PMD page.\n-\t\t\t * There is no way of knowing exactly which PMDs may\n-\t\t\t * be cached for this mm, so we must flush them all.\n-\t\t\t * start/end were already adjusted above to cover this\n-\t\t\t * range.\n-\t\t\t */\n-\t\t\tflush_cache_range(vma, range.start, range.end);\n-\n-\t\t\t/*\n-\t\t\t * To call huge_pmd_unshare, i_mmap_rwsem must be\n-\t\t\t * held in write mode.  Caller needs to explicitly\n-\t\t\t * do this outside rmap routines.\n-\t\t\t *\n-\t\t\t * We also must hold hugetlb vma_lock in write mode.\n-\t\t\t * Lock order dictates acquiring vma_lock BEFORE\n-\t\t\t * i_mmap_rwsem.  We can only try lock here and fail\n-\t\t\t * if unsuccessful.\n-\t\t\t */\n-\t\t\tif (!anon) {\n-\t\t\t\tstruct mmu_gather tlb;\n-\n-\t\t\t\tVM_BUG_ON(!(flags \u0026 TTU_RMAP_LOCKED));\n-\t\t\t\tif (!hugetlb_vma_trylock_write(vma))\n-\t\t\t\t\tgoto walk_abort;\n-\n-\t\t\t\ttlb_gather_mmu_vma(\u0026tlb, vma);\n-\t\t\t\tif (huge_pmd_unshare(\u0026tlb, vma, address, pvmw.pte)) {\n-\t\t\t\t\thugetlb_vma_unlock_write(vma);\n-\t\t\t\t\thuge_pmd_unshare_flush(\u0026tlb, vma);\n-\t\t\t\t\ttlb_finish_mmu(\u0026tlb);\n-\t\t\t\t\t/*\n-\t\t\t\t\t * The PMD table was unmapped,\n-\t\t\t\t\t * consequently unmapping the folio.\n-\t\t\t\t\t */\n-\t\t\t\t\tgoto walk_done;\n-\t\t\t\t}\n-\t\t\t\thugetlb_vma_unlock_write(vma);\n-\t\t\t\ttlb_finish_mmu(\u0026tlb);\n-\t\t\t}\n-\t\t\tpteval = huge_ptep_clear_flush(vma, address, pvmw.pte);\n-\t\t\tif (pte_dirty(pteval))\n-\t\t\t\tfolio_mark_dirty(folio);\n-\t\t} else if (likely(pte_present(pteval))) {\n+\t\tif (likely(pte_present(pteval))) {\n \t\t\tnr_pages = folio_unmap_pte_batch(folio, \u0026pvmw, flags, pteval);\n \t\t\tend_addr = address + nr_pages * PAGE_SIZE;\n \t\t\tflush_cache_range(vma, address, end_addr);\n@@ -2204,16 +2363,14 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t/* Update high watermark before we lower rss */\n \t\tupdate_hiwater_rss(mm);\n \n-\t\tif (PageHWPoison(subpage) \u0026\u0026 (flags \u0026 TTU_HWPOISON)) {\n+\t\t/*\n+\t\t * With TTU_HWPOISON, we only expect small folios or hugetlb\n+\t\t * folios here for now.\n+\t\t */\n+\t\tif (folio_test_hwpoison(folio) \u0026\u0026 (flags \u0026 TTU_HWPOISON)) {\n \t\t\tpteval = swp_entry_to_pte(make_hwpoison_entry(subpage));\n-\t\t\tif (folio_test_hugetlb(folio)) {\n-\t\t\t\thugetlb_count_sub(folio_nr_pages(folio), mm);\n-\t\t\t\tset_huge_pte_at(mm, address, pvmw.pte, pteval,\n-\t\t\t\t\t\thsz);\n-\t\t\t} else {\n-\t\t\t\tdec_mm_counter(mm, mm_counter(folio));\n-\t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n-\t\t\t}\n+\t\t\tdec_mm_counter(mm, mm_counter(folio));\n+\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n \t\t} else if (likely(pte_present(pteval)) \u0026\u0026 pte_unused(pteval) \u0026\u0026\n \t\t\t   !userfaultfd_armed(vma)) {\n \t\t\t/*\n@@ -2228,104 +2385,11 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t */\n \t\t\tdec_mm_counter(mm, mm_counter(folio));\n \t\t} else if (folio_test_anon(folio)) {\n-\t\t\tswp_entry_t entry = page_swap_entry(subpage);\n-\t\t\tpte_t swp_pte;\n-\t\t\t/*\n-\t\t\t * Store the swap location in the pte.\n-\t\t\t * See handle_pte_fault() ...\n-\t\t\t */\n-\t\t\tif (unlikely(folio_test_swapbacked(folio) !=\n-\t\t\t\t\tfolio_test_swapcache(folio))) {\n-\t\t\t\tWARN_ON_ONCE(1);\n+\t\t\tif (!ttu_anon_folio(vma, folio, subpage, address,\n+\t\t\t\t\t    pvmw.pte, pteval, nr_pages))\n \t\t\t\tgoto walk_abort;\n-\t\t\t}\n-\n-\t\t\t/* MADV_FREE page check */\n-\t\t\tif (!folio_test_swapbacked(folio)) {\n-\t\t\t\tint ref_count, map_count;\n-\n-\t\t\t\t/*\n-\t\t\t\t * Synchronize with gup_pte_range():\n-\t\t\t\t * - clear PTE; barrier; read refcount\n-\t\t\t\t * - inc refcount; barrier; read PTE\n-\t\t\t\t */\n-\t\t\t\tsmp_mb();\n \n-\t\t\t\tref_count = folio_ref_count(folio);\n-\t\t\t\tmap_count = folio_mapcount(folio);\n-\n-\t\t\t\t/*\n-\t\t\t\t * Order reads for page refcount and dirty flag\n-\t\t\t\t * (see comments in __remove_mapping()).\n-\t\t\t\t */\n-\t\t\t\tsmp_rmb();\n-\n-\t\t\t\tif (folio_test_dirty(folio) \u0026\u0026 !(vma-\u003evm_flags \u0026 VM_DROPPABLE)) {\n-\t\t\t\t\t/*\n-\t\t\t\t\t * redirtied either using the page table or a previously\n-\t\t\t\t\t * obtained GUP reference.\n-\t\t\t\t\t */\n-\t\t\t\t\tset_ptes(mm, address, pvmw.pte, pteval, nr_pages);\n-\t\t\t\t\tfolio_set_swapbacked(folio);\n-\t\t\t\t\tgoto walk_abort;\n-\t\t\t\t} else if (ref_count != 1 + map_count) {\n-\t\t\t\t\t/*\n-\t\t\t\t\t * Additional reference. Could be a GUP reference or any\n-\t\t\t\t\t * speculative reference. GUP users must mark the folio\n-\t\t\t\t\t * dirty if there was a modification. This folio cannot be\n-\t\t\t\t\t * reclaimed right now either way, so act just like nothing\n-\t\t\t\t\t * happened.\n-\t\t\t\t\t * We'll come back here later and detect if the folio was\n-\t\t\t\t\t * dirtied when the additional reference is gone.\n-\t\t\t\t\t */\n-\t\t\t\t\tset_ptes(mm, address, pvmw.pte, pteval, nr_pages);\n-\t\t\t\t\tgoto walk_abort;\n-\t\t\t\t}\n-\t\t\t\tadd_mm_counter(mm, MM_ANONPAGES, -nr_pages);\n-\t\t\t\tgoto discard;\n-\t\t\t}\n-\n-\t\t\tif (folio_dup_swap(folio, subpage) \u003c 0) {\n-\t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n-\t\t\t\tgoto walk_abort;\n-\t\t\t}\n-\n-\t\t\t/*\n-\t\t\t * arch_unmap_one() is expected to be a NOP on\n-\t\t\t * architectures where we could have PFN swap PTEs,\n-\t\t\t * so we'll not check/care.\n-\t\t\t */\n-\t\t\tif (arch_unmap_one(mm, vma, address, pteval) \u003c 0) {\n-\t\t\t\tfolio_put_swap(folio, subpage);\n-\t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n-\t\t\t\tgoto walk_abort;\n-\t\t\t}\n-\n-\t\t\t/* See folio_try_share_anon_rmap(): clear PTE first. */\n-\t\t\tif (anon_exclusive \u0026\u0026\n-\t\t\t    folio_try_share_anon_rmap_pte(folio, subpage)) {\n-\t\t\t\tfolio_put_swap(folio, subpage);\n-\t\t\t\tset_pte_at(mm, address, pvmw.pte, pteval);\n-\t\t\t\tgoto walk_abort;\n-\t\t\t}\n-\t\t\tmm_prepare_for_swap_entries(mm);\n-\t\t\tdec_mm_counter(mm, MM_ANONPAGES);\n-\t\t\tinc_mm_counter(mm, MM_SWAPENTS);\n-\t\t\tswp_pte = swp_entry_to_pte(entry);\n-\t\t\tif (anon_exclusive)\n-\t\t\t\tswp_pte = pte_swp_mkexclusive(swp_pte);\n-\t\t\tif (likely(pte_present(pteval))) {\n-\t\t\t\tif (pte_soft_dirty(pteval))\n-\t\t\t\t\tswp_pte = pte_swp_mksoft_dirty(swp_pte);\n-\t\t\t\tif (pte_uffd_wp(pteval))\n-\t\t\t\t\tswp_pte = pte_swp_mkuffd_wp(swp_pte);\n-\t\t\t} else {\n-\t\t\t\tif (pte_swp_soft_dirty(pteval))\n-\t\t\t\t\tswp_pte = pte_swp_mksoft_dirty(swp_pte);\n-\t\t\t\tif (pte_swp_uffd_wp(pteval))\n-\t\t\t\t\tswp_pte = pte_swp_mkuffd_wp(swp_pte);\n-\t\t\t}\n-\t\t\tset_pte_at(mm, address, pvmw.pte, swp_pte);\n+\t\t\tgoto finish_unmap;\n \t\t} else {\n \t\t\t/*\n \t\t\t * This is a locked file-backed folio,\n@@ -2340,12 +2404,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t */\n \t\t\tadd_mm_counter(mm, mm_counter_file(folio), -nr_pages);\n \t\t}\n-discard:\n-\t\tif (unlikely(folio_test_hugetlb(folio))) {\n-\t\t\thugetlb_remove_rmap(folio);\n-\t\t} else {\n-\t\t\tfolio_remove_rmap_ptes(folio, subpage, nr_pages, vma);\n-\t\t}\n+finish_unmap:\n+\t\tfolio_remove_rmap_ptes(folio, subpage, nr_pages, vma);\n \t\tif (vma-\u003evm_flags \u0026 VM_LOCKED)\n \t\t\tmlock_drain_local();\n \t\tfolio_put_refs(folio, nr_pages);\n@@ -2393,7 +2453,8 @@ static int folio_not_mapped(struct folio *folio)\n void try_to_unmap(struct folio *folio, enum ttu_flags flags)\n {\n \tstruct rmap_walk_control rwc = {\n-\t\t.rmap_one = try_to_unmap_one,\n+\t\t.rmap_one = folio_test_hugetlb(folio) ?\n+\t\t\t\ttry_to_unmap_hugetlb_one : try_to_unmap_one,\n \t\t.arg = (void *)flags,\n \t\t.done = folio_not_mapped,\n \t\t.anon_lock = folio_lock_anon_vma_read,\n"
}

2/1 2026/07/07 20:37 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "HUGETLBFS",
    "SWAP",
    "MEMORY_FAILURE",
    "HWPOISON_INJECT"
  ],
  "FocusSymbols": [
    "try_to_unmap_hugetlb_one",
    "ttu_anon_folio",
    "ttu_anon_lazyfree_folio",
    "ttu_anon_swapbacked_folio",
    "try_to_unmap_one"
  ],
  "Reasoning": "The patch refactors the unmapping logic in mm/rmap.c by extracting hugetlb and anonymous folio unmapping into separate functions (try_to_unmap_hugetlb_one, ttu_anon_folio, etc.). It modifies core memory management logic related to reverse mapping, huge pages, and swap. Fuzzing should focus on these new functions to ensure no regressions or bugs were introduced during the refactoring.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a '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:
For your convenience, here is the diff of the changes:
commit 1e84bc0e0c206f915008ad4c71905ceb278b1c58
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Jul 7 20:37:44 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 4115076e4922ae..bf7e163e3779d8 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -1271,6 +1271,7 @@ static inline void hugetlb_count_sub(long l, struct mm_struct *mm)
 }
 
 pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+unsigned long huge_pte_dirty(pte_t pte);
 
 static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
 					  unsigned long addr, pte_t *ptep)
diff --git a/mm/rmap.c b/mm/rmap.c
index 9939400e77c79a..f021ecd51a4a2e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1978,6 +1978,233 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
 				     FPB_RESPECT_WRITE | FPB_RESPECT_SOFT_DIRTY);
 }
 
+static bool try_to_unmap_hugetlb_one(struct folio *folio,
+		struct vm_area_struct *vma, unsigned long address, void *arg)
+{
+	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
+	struct mmu_notifier_range range;
+	enum ttu_flags flags = (enum ttu_flags)(long)arg;
+	struct mm_struct *mm = vma->vm_mm;
+	const unsigned long hsz = huge_page_size(hstate_vma(vma));
+	bool ret = true;
+	pte_t pteval;
+
+	/*
+	 * The try_to_unmap() is only passed a hugetlb folio in the case
+	 * where the hugetlb folio is poisoned.
+	 */
+	VM_WARN_ON_FOLIO(!folio_test_hwpoison(folio), folio);
+	VM_WARN_ON_ONCE(!(flags & TTU_HWPOISON));
+
+	range.end = vma_address_end(&pvmw);
+	mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma->vm_mm,
+				address, range.end);
+	adjust_range_if_pmd_sharing_possible(vma, &range.start, &range.end);
+	mmu_notifier_invalidate_range_start(&range);
+
+	/* There is only a single mapping in a VMA. */
+	if (!page_vma_mapped_walk(&pvmw))
+		goto range_end;
+
+	address = pvmw.address;
+	pteval = huge_ptep_get(mm, address, pvmw.pte);
+	VM_WARN_ON_ONCE(!pte_present(pteval));
+	VM_WARN_ON_ONCE(pte_pfn(pteval) != folio_pfn(folio));
+
+	/*
+	 * huge_pmd_unshare may unmap an entire PMD page. There is no way of
+	 * knowing exactly which PMDs may be cached for this mm, so we must
+	 * flush them all. start/end were already adjusted above to cover this
+	 * range.
+	 */
+	flush_cache_range(vma, range.start, range.end);
+
+	/*
+	 * To call huge_pmd_unshare, i_mmap_rwsem must be held in write mode.
+	 * Caller needs to explicitly do this outside rmap routines.
+	 *
+	 * We also must hold hugetlb vma_lock in write mode. Lock order dictates
+	 * acquiring vma_lock BEFORE i_mmap_rwsem. We can only try lock here and
+	 * fail if unsuccessful.
+	 */
+	if (!folio_test_anon(folio)) {
+		struct mmu_gather tlb;
+
+		VM_WARN_ON(!(flags & TTU_RMAP_LOCKED));
+		if (!hugetlb_vma_trylock_write(vma)) {
+			ret = false;
+			goto walk_done;
+		}
+
+		tlb_gather_mmu_vma(&tlb, vma);
+		if (huge_pmd_unshare(&tlb, vma, address, pvmw.pte)) {
+			hugetlb_vma_unlock_write(vma);
+			huge_pmd_unshare_flush(&tlb, vma);
+			tlb_finish_mmu(&tlb);
+			/*
+			 * The PMD table was unmapped, consequently unmapping
+			 * the folio.
+			 */
+			goto walk_done;
+		}
+		hugetlb_vma_unlock_write(vma);
+		tlb_finish_mmu(&tlb);
+	}
+	pteval = huge_ptep_clear_flush(vma, address, pvmw.pte);
+	if (huge_pte_dirty(pteval))
+		folio_mark_dirty(folio);
+
+	pteval = swp_entry_to_pte(make_hwpoison_entry(folio_page(folio, 0)));
+	hugetlb_count_sub(folio_nr_pages(folio), mm);
+	set_huge_pte_at(mm, address, pvmw.pte, pteval, hsz);
+	hugetlb_remove_rmap(folio);
+	folio_put_refs(folio, 1);
+
+walk_done:
+	page_vma_mapped_walk_done(&pvmw);
+range_end:
+	mmu_notifier_invalidate_range_end(&range);
+	return ret;
+}
+
+static inline bool ttu_anon_lazyfree_folio(struct vm_area_struct *vma,
+		struct folio *folio)
+{
+	int ref_count, map_count;
+
+	/*
+	 * Synchronize with gup_pte_range():
+	 * - clear PTE; barrier; read refcount
+	 * - inc refcount; barrier; read PTE
+	 */
+	smp_mb();
+
+	ref_count = folio_ref_count(folio);
+	map_count = folio_mapcount(folio);
+
+	/*
+	 * Order reads for page refcount and dirty flag
+	 * (see comments in __remove_mapping()).
+	 */
+	smp_rmb();
+
+	if (folio_test_dirty(folio) && !(vma->vm_flags & VM_DROPPABLE)) {
+		/*
+		 * redirtied either using the page table or a previously
+		 * obtained GUP reference.
+		 */
+		folio_set_swapbacked(folio);
+		return false;
+	}
+
+	if (ref_count != 1 + map_count) {
+		/*
+		 * Additional reference. Could be a GUP reference or any
+		 * speculative reference. GUP users must mark the folio
+		 * dirty if there was a modification. This folio cannot be
+		 * reclaimed right now either way, so act just like nothing
+		 * happened.
+		 * We'll come back here later and detect if the folio was
+		 * dirtied when the additional reference is gone.
+		 */
+		return false;
+	}
+
+	return true;
+}
+
+static inline void set_swp_pte_at(struct mm_struct *mm, unsigned long address,
+		pte_t *ptep, swp_entry_t entry, pte_t pteval, bool anon_exclusive)
+{
+	pte_t swp_pte = swp_entry_to_pte(entry);
+
+	if (anon_exclusive)
+		swp_pte = pte_swp_mkexclusive(swp_pte);
+
+	if (likely(pte_present(pteval))) {
+		if (pte_soft_dirty(pteval))
+			swp_pte = pte_swp_mksoft_dirty(swp_pte);
+		if (pte_uffd_wp(pteval))
+			swp_pte = pte_swp_mkuffd_wp(swp_pte);
+	} else {
+		/* Device-exclusive entry */
+		if (pte_swp_soft_dirty(pteval))
+			swp_pte = pte_swp_mksoft_dirty(swp_pte);
+		if (pte_swp_uffd_wp(pteval))
+			swp_pte = pte_swp_mkuffd_wp(swp_pte);
+	}
+
+	set_pte_at(mm, address, ptep, swp_pte);
+}
+
+static inline bool ttu_anon_swapbacked_folio(struct vm_area_struct *vma, struct folio *folio,
+		struct page *subpage, unsigned long address, pte_t *ptep,
+		pte_t pteval)
+{
+	bool anon_exclusive = folio_test_anon(folio) && PageAnonExclusive(subpage);
+	swp_entry_t entry = page_swap_entry(subpage);
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (folio_dup_swap(folio, subpage) < 0)
+		return false;
+
+	/*
+	 * arch_unmap_one() is expected to be a NOP on
+	 * architectures where we could have PFN swap PTEs,
+	 * so we'll not check/care.
+	 */
+	if (arch_unmap_one(mm, vma, address, pteval) < 0) {
+		folio_put_swap(folio, subpage);
+		return false;
+	}
+
+	/* See folio_try_share_anon_rmap(): clear PTE first. */
+	if (anon_exclusive && folio_try_share_anon_rmap_pte(folio, subpage)) {
+		folio_put_swap(folio, subpage);
+		return false;
+	}
+
+	mm_prepare_for_swap_entries(mm);
+	dec_mm_counter(mm, MM_ANONPAGES);
+	inc_mm_counter(mm, MM_SWAPENTS);
+	set_swp_pte_at(mm, address, ptep, entry, pteval, anon_exclusive);
+	return true;
+}
+
+static inline bool ttu_anon_folio(struct vm_area_struct *vma, struct folio *folio,
+		struct page *subpage, unsigned long address, pte_t *ptep,
+		pte_t pteval, unsigned long nr_pages)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	bool ret;
+
+	/*
+	 * Store the swap location in the pte.
+	 * See handle_pte_fault() ...
+	 */
+	if (unlikely(folio_test_swapbacked(folio) !=
+			folio_test_swapcache(folio))) {
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	/* MADV_FREE page check */
+	if (!folio_test_swapbacked(folio)) {
+		ret = ttu_anon_lazyfree_folio(vma, folio);
+		if (ret)
+			add_mm_counter(mm, MM_ANONPAGES, -nr_pages);
+	} else {
+		/* nr_pages > 1 not supported yet */
+		ret = ttu_anon_swapbacked_folio(vma, folio, subpage, address,
+						ptep, pteval);
+	}
+
+	if (!ret)
+		set_ptes(mm, address, ptep, pteval, nr_pages);
+
+	return ret;
+}
+
 /*
  * @arg: enum ttu_flags will be passed to this argument
  */
@@ -1986,14 +2213,13 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 {
 	struct mm_struct *mm = vma->vm_mm;
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
-	bool anon_exclusive, ret = true;
+	bool ret = true;
 	pte_t pteval;
 	struct page *subpage;
 	struct mmu_notifier_range range;
 	enum ttu_flags flags = (enum ttu_flags)(long)arg;
 	unsigned long nr_pages = 1, end_addr;
 	unsigned long pfn;
-	unsigned long hsz = 0;
 	int ptes = 0;
 
 	/*
@@ -2007,8 +2233,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 
 	/*
 	 * For THP, we have to assume the worse case ie pmd for invalidation.
-	 * For hugetlb, it could be much worse if we need to do pud
-	 * invalidation in the case of pmd sharing.
 	 *
 	 * Note that the folio can not be freed in this function as call of
 	 * try_to_unmap() must hold a reference on the folio.
@@ -2016,17 +2240,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 	range.end = vma_address_end(&pvmw);
 	mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma->vm_mm,
 				address, range.end);
-	if (folio_test_hugetlb(folio)) {
-		/*
-		 * If sharing is possible, start and end will be adjusted
-		 * accordingly.
-		 */
-		adjust_range_if_pmd_sharing_possible(vma, &range.start,
-						     &range.end);
-
-		/* We need the huge page size for set_huge_pte_at() */
-		hsz = huge_page_size(hstate_vma(vma));
-	}
 	mmu_notifier_invalidate_range_start(&range);
 
 	while (page_vma_mapped_walk(&pvmw)) {
@@ -2111,65 +2324,11 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			const softleaf_t entry = softleaf_from_pte(pteval);
 
 			pfn = softleaf_to_pfn(entry);
-			VM_WARN_ON_FOLIO(folio_test_hugetlb(folio), folio);
 		}
 
 		subpage = folio_page(folio, pfn - folio_pfn(folio));
-		anon_exclusive = folio_test_anon(folio) &&
-				 PageAnonExclusive(subpage);
 
-		if (folio_test_hugetlb(folio)) {
-			bool anon = folio_test_anon(folio);
-
-			/*
-			 * The try_to_unmap() is only passed a hugetlb page
-			 * in the case where the hugetlb page is poisoned.
-			 */
-			VM_BUG_ON_PAGE(!PageHWPoison(subpage), subpage);
-			/*
-			 * huge_pmd_unshare may unmap an entire PMD page.
-			 * There is no way of knowing exactly which PMDs may
-			 * be cached for this mm, so we must flush them all.
-			 * start/end were already adjusted above to cover this
-			 * range.
-			 */
-			flush_cache_range(vma, range.start, range.end);
-
-			/*
-			 * To call huge_pmd_unshare, i_mmap_rwsem must be
-			 * held in write mode.  Caller needs to explicitly
-			 * do this outside rmap routines.
-			 *
-			 * We also must hold hugetlb vma_lock in write mode.
-			 * Lock order dictates acquiring vma_lock BEFORE
-			 * i_mmap_rwsem.  We can only try lock here and fail
-			 * if unsuccessful.
-			 */
-			if (!anon) {
-				struct mmu_gather tlb;
-
-				VM_BUG_ON(!(flags & TTU_RMAP_LOCKED));
-				if (!hugetlb_vma_trylock_write(vma))
-					goto walk_abort;
-
-				tlb_gather_mmu_vma(&tlb, vma);
-				if (huge_pmd_unshare(&tlb, vma, address, pvmw.pte)) {
-					hugetlb_vma_unlock_write(vma);
-					huge_pmd_unshare_flush(&tlb, vma);
-					tlb_finish_mmu(&tlb);
-					/*
-					 * The PMD table was unmapped,
-					 * consequently unmapping the folio.
-					 */
-					goto walk_done;
-				}
-				hugetlb_vma_unlock_write(vma);
-				tlb_finish_mmu(&tlb);
-			}
-			pteval = huge_ptep_clear_flush(vma, address, pvmw.pte);
-			if (pte_dirty(pteval))
-				folio_mark_dirty(folio);
-		} else if (likely(pte_present(pteval))) {
+		if (likely(pte_present(pteval))) {
 			nr_pages = folio_unmap_pte_batch(folio, &pvmw, flags, pteval);
 			end_addr = address + nr_pages * PAGE_SIZE;
 			flush_cache_range(vma, address, end_addr);
@@ -2204,16 +2363,14 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		/* Update high watermark before we lower rss */
 		update_hiwater_rss(mm);
 
-		if (PageHWPoison(subpage) && (flags & TTU_HWPOISON)) {
+		/*
+		 * With TTU_HWPOISON, we only expect small folios or hugetlb
+		 * folios here for now.
+		 */
+		if (folio_test_hwpoison(folio) && (flags & TTU_HWPOISON)) {
 			pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
-			if (folio_test_hugetlb(folio)) {
-				hugetlb_count_sub(folio_nr_pages(folio), mm);
-				set_huge_pte_at(mm, address, pvmw.pte, pteval,
-						hsz);
-			} else {
-				dec_mm_counter(mm, mm_counter(folio));
-				set_pte_at(mm, address, pvmw.pte, pteval);
-			}
+			dec_mm_counter(mm, mm_counter(folio));
+			set_pte_at(mm, address, pvmw.pte, pteval);
 		} else if (likely(pte_present(pteval)) && pte_unused(pteval) &&
 			   !userfaultfd_armed(vma)) {
 			/*
@@ -2228,104 +2385,11 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 */
 			dec_mm_counter(mm, mm_counter(folio));
 		} else if (folio_test_anon(folio)) {
-			swp_entry_t entry = page_swap_entry(subpage);
-			pte_t swp_pte;
-			/*
-			 * Store the swap location in the pte.
-			 * See handle_pte_fault() ...
-			 */
-			if (unlikely(folio_test_swapbacked(folio) !=
-					folio_test_swapcache(folio))) {
-				WARN_ON_ONCE(1);
+			if (!ttu_anon_folio(vma, folio, subpage, address,
+					    pvmw.pte, pteval, nr_pages))
 				goto walk_abort;
-			}
-
-			/* MADV_FREE page check */
-			if (!folio_test_swapbacked(folio)) {
-				int ref_count, map_count;
-
-				/*
-				 * Synchronize with gup_pte_range():
-				 * - clear PTE; barrier; read refcount
-				 * - inc refcount; barrier; read PTE
-				 */
-				smp_mb();
 
-				ref_count = folio_ref_count(folio);
-				map_count = folio_mapcount(folio);
-
-				/*
-				 * Order reads for page refcount and dirty flag
-				 * (see comments in __remove_mapping()).
-				 */
-				smp_rmb();
-
-				if (folio_test_dirty(folio) && !(vma->vm_flags & VM_DROPPABLE)) {
-					/*
-					 * redirtied either using the page table or a previously
-					 * obtained GUP reference.
-					 */
-					set_ptes(mm, address, pvmw.pte, pteval, nr_pages);
-					folio_set_swapbacked(folio);
-					goto walk_abort;
-				} else if (ref_count != 1 + map_count) {
-					/*
-					 * Additional reference. Could be a GUP reference or any
-					 * speculative reference. GUP users must mark the folio
-					 * dirty if there was a modification. This folio cannot be
-					 * reclaimed right now either way, so act just like nothing
-					 * happened.
-					 * We'll come back here later and detect if the folio was
-					 * dirtied when the additional reference is gone.
-					 */
-					set_ptes(mm, address, pvmw.pte, pteval, nr_pages);
-					goto walk_abort;
-				}
-				add_mm_counter(mm, MM_ANONPAGES, -nr_pages);
-				goto discard;
-			}
-
-			if (folio_dup_swap(folio, subpage) < 0) {
-				set_pte_at(mm, address, pvmw.pte, pteval);
-				goto walk_abort;
-			}
-
-			/*
-			 * arch_unmap_one() is expected to be a NOP on
-			 * architectures where we could have PFN swap PTEs,
-			 * so we'll not check/care.
-			 */
-			if (arch_unmap_one(mm, vma, address, pteval) < 0) {
-				folio_put_swap(folio, subpage);
-				set_pte_at(mm, address, pvmw.pte, pteval);
-				goto walk_abort;
-			}
-
-			/* See folio_try_share_anon_rmap(): clear PTE first. */
-			if (anon_exclusive &&
-			    folio_try_share_anon_rmap_pte(folio, subpage)) {
-				folio_put_swap(folio, subpage);
-				set_pte_at(mm, address, pvmw.pte, pteval);
-				goto walk_abort;
-			}
-			mm_prepare_for_swap_entries(mm);
-			dec_mm_counter(mm, MM_ANONPAGES);
-			inc_mm_counter(mm, MM_SWAPENTS);
-			swp_pte = swp_entry_to_pte(entry);
-			if (anon_exclusive)
-				swp_pte = pte_swp_mkexclusive(swp_pte);
-			if (likely(pte_present(pteval))) {
-				if (pte_soft_dirty(pteval))
-					swp_pte = pte_swp_mksoft_dirty(swp_pte);
-				if (pte_uffd_wp(pteval))
-					swp_pte = pte_swp_mkuffd_wp(swp_pte);
-			} else {
-				if (pte_swp_soft_dirty(pteval))
-					swp_pte = pte_swp_mksoft_dirty(swp_pte);
-				if (pte_swp_uffd_wp(pteval))
-					swp_pte = pte_swp_mkuffd_wp(swp_pte);
-			}
-			set_pte_at(mm, address, pvmw.pte, swp_pte);
+			goto finish_unmap;
 		} else {
 			/*
 			 * This is a locked file-backed folio,
@@ -2340,12 +2404,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 			 */
 			add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
 		}
-discard:
-		if (unlikely(folio_test_hugetlb(folio))) {
-			hugetlb_remove_rmap(folio);
-		} else {
-			folio_remove_rmap_ptes(folio, subpage, nr_pages, vma);
-		}
+finish_unmap:
+		folio_remove_rmap_ptes(folio, subpage, nr_pages, vma);
 		if (vma->vm_flags & VM_LOCKED)
 			mlock_drain_local();
 		folio_put_refs(folio, nr_pages);
@@ -2393,7 +2453,8 @@ static int folio_not_mapped(struct folio *folio)
 void try_to_unmap(struct folio *folio, enum ttu_flags flags)
 {
 	struct rmap_walk_control rwc = {
-		.rmap_one = try_to_unmap_one,
+		.rmap_one = folio_test_hugetlb(folio) ?
+				try_to_unmap_hugetlb_one : try_to_unmap_one,
 		.arg = (void *)flags,
 		.done = folio_not_mapped,
 		.anon_lock = folio_lock_anon_vma_read,

3/2 2026/07/07 20:37 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 8352
							output: 26
							thoughts: 314
						

Thoughts:
**Analyzing the `mm/rmap.c` Refactoring for Potential Vulnerabilities**

Okay, so I'm looking at this patch. It's touching `mm/rmap.c` and `include/linux/hugetlb.h`, which immediately flags some serious attention. It looks like we're refactoring `try_to_unmap_one` to be cleaner, pulling out the hugetlb-specific stuff into `try_to_unmap_hugetlb_one`, and then handling anonymous folio cases with a handful of new functions: `ttu_anon_folio`, `ttu_anon_lazyfree_folio`, and `ttu_anon_swapbacked_folio`. The main `try_to_unmap` function is now conditionally calling `try_to_unmap_hugetlb_one` if the folio is a hugetlb page.

Functionally, this seems like mostly a refactoring. But let's be honest, any change in these core memory management areas – rmap, hugetlb, unmapping – warrants a *very* close look. These are critical paths, and subtle errors can have devastating consequences. My primary concern here is that this kind of refactoring is prone to introducing off-by-one errors, incorrect locking, or other subtle bugs due to the complexity involved.

So, I need to focus my fuzzing efforts. The key functions to target are:

*   `try_to_unmap_hugetlb_one` - This is now handling the hugetlb specific logic, which, due to their size, introduce complexities that may not be apparent in general folio pages.
*   `ttu_anon_folio` - This is now handling general anonymous folios.
*   `ttu_anon_lazyfree_folio` - This is now handling anonymous lazy-free folios.
*   `ttu_anon_swapbacked_folio` - This is now handling anonymous folios that have swap backing.
*   `try_to_unmap` - The main entry point, and the function where the control flow branches.

And of course, I need to make sure the fuzzing environment is appropriately configured. We'll need to enable `HUGETLB_PAGE`, of course, for hugetlb testing. The presence of swap-backed folios calls for the `SWAP` config to be enabled. And since there's some mention of `TTU_HWPOISON` logic within, I need to have either `HWPOISON_INJECT` or `MEMORY_FAILURE` enabled.

Right. Time to verify those configs and start digging into the code.



4/2 2026/07/07 20:37 tool grepper
0m Args:
{
  "Expression": "try_to_unmap_hugetlb_one"
}

Results:
{
  "Output": "mm/rmap.c=1944=static inline unsigned int folio_unmap_pte_batch(struct folio *folio,\n--\nmm/rmap.c-1980-\nmm/rmap.c:1981:static bool try_to_unmap_hugetlb_one(struct folio *folio,\nmm/rmap.c-1982-\t\tstruct vm_area_struct *vma, unsigned long address, void *arg)\n--\nmm/rmap.c=2453=void try_to_unmap(struct folio *folio, enum ttu_flags flags)\n--\nmm/rmap.c-2456-\t\t.rmap_one = folio_test_hugetlb(folio) ?\nmm/rmap.c:2457:\t\t\t\ttry_to_unmap_hugetlb_one : try_to_unmap_one,\nmm/rmap.c-2458-\t\t.arg = (void *)flags,\n"
}

5/2 2026/07/07 20:37 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9491
							output: 20
							thoughts: 13
						

Thoughts:
Here's my thought process, summarized as you requested:

**Kconfig and Huge Pages: A Quick Check**

Okay, before diving any deeper, I need to make absolutely sure the kernel configuration for HugeTLB pages is properly set. It's easy to overlook, and a misconfiguration here would throw everything off. So, I need to open the `Kconfig` files and search for `HUGETLB_PAGE`. That's the baseline. I need to verify its status - is it enabled, disabled, or set to some specific value? A quick scan of the relevant Kconfig options will immediately tell me if I'm even *able* to work with hugetlbfs. This is just a sanity check; don't waste time on anything else yet.



6/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "config HUGETLB_PAGE"
}

Results:
{
  "Output": "arch/sh/mm/Kconfig=158=choice\n--\narch/sh/mm/Kconfig-163-\narch/sh/mm/Kconfig:164:config HUGETLB_PAGE_SIZE_64K\narch/sh/mm/Kconfig-165-\tbool \"64kB\"\n--\narch/sh/mm/Kconfig-167-\narch/sh/mm/Kconfig:168:config HUGETLB_PAGE_SIZE_256K\narch/sh/mm/Kconfig-169-\tbool \"256kB\"\n--\narch/sh/mm/Kconfig-171-\narch/sh/mm/Kconfig:172:config HUGETLB_PAGE_SIZE_1MB\narch/sh/mm/Kconfig-173-\tbool \"1MB\"\narch/sh/mm/Kconfig-174-\narch/sh/mm/Kconfig:175:config HUGETLB_PAGE_SIZE_4MB\narch/sh/mm/Kconfig-176-\tbool \"4MB\"\n--\narch/sh/mm/Kconfig-178-\narch/sh/mm/Kconfig:179:config HUGETLB_PAGE_SIZE_64MB\narch/sh/mm/Kconfig-180-\tbool \"64MB\"\n--\nfs/Kconfig=262=if HUGETLBFS\nfs/Kconfig:263:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON\nfs/Kconfig-264-\tbool \"HugeTLB Vmemmap Optimization (HVO) defaults to on\"\n--\nfs/Kconfig=271=endif # HUGETLBFS\nfs/Kconfig-272-\nfs/Kconfig:273:config HUGETLB_PAGE\nfs/Kconfig-274-\tdef_bool HUGETLBFS\n--\nfs/Kconfig-276-\nfs/Kconfig:277:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP\nfs/Kconfig-278-\tdef_bool HUGETLB_PAGE\n--\nmm/Kconfig=706=config ARCH_HAS_PMD_SOFTLEAVES\n--\nmm/Kconfig-708-\nmm/Kconfig:709:config HUGETLB_PAGE_SIZE_VARIABLE\nmm/Kconfig-710-\tdef_bool n\n"
}

7/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10282
							output: 19
							thoughts: 30
						

Thoughts:
Okay, here's my interpretation of those thoughts, presented as my own mental process, given my expertise:

**Diving into the HugeTLB Configuration**

Alright, so `HUGETLB_PAGE` is the target here. That's a good starting point for investigating the huge page support. And the Kconfig entry mentions a dependency: `HUGETLBFS`. Right, so this confirms the dependency. I need to understand this `HUGETLBFS` component to fully grasp the capabilities of `HUGETLB_PAGE`. Let me quickly shift my focus and start looking into the details of what `HUGETLBFS` brings to the table. Time to dig deeper into the file system side of this.



8/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "config HUGETLBFS"
}

Results:
{
  "Output": "fs/Kconfig=247=config ARCH_SUPPORTS_HUGETLBFS\n--\nfs/Kconfig-249-\nfs/Kconfig:250:menuconfig HUGETLBFS\nfs/Kconfig-251-\tbool \"HugeTLB file system support\"\n"
}

9/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10560
							output: 19
							thoughts: 23
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:

**Kernel Configuration Deep Dive**

Alright, so I'm diving into this kernel configuration, and the key thing I'm immediately homing in on is `HUGETLBFS`. That's the one I need to enable for the use case we're considering, no doubt. Now, before I proceed with any more of these changes, let's just do a quick double-check of something related, to ensure we are covering the bases. Let's make sure that `MEMORY_FAILURE` is set to the correct value, since that has implications for the overall memory management strategy, and how it will interact with this new setup. Just want to make sure the interactions are as expected.



10/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "config MEMORY_FAILURE"
}

Results:
{
  "Output": "mm/Kconfig=774=config ARCH_SUPPORTS_MEMORY_FAILURE\n--\nmm/Kconfig-776-\nmm/Kconfig:777:config MEMORY_FAILURE\nmm/Kconfig-778-\tdepends on MMU\n"
}

11/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 10843
							output: 21
							thoughts: 12
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Deep Dive on `HWPOISON_INJECT`**

Alright, time to circle back and give `HWPOISON_INJECT` a proper once-over. This likely means I'm looking for a particular interaction or potential vulnerability related to hardware-based memory corruption. I need to understand what specific poison values are being introduced, how they are being injected, and the conditions under which this injection is occurring. I'll need to think through the possible impact, maybe considering how this relates to mitigation techniques like memory tagging or error-correcting codes, and how this feature might interact with other hardware features or software subsystems. I need to assess the scope of this poisoning and potential impact on system stability, security, or data integrity. Ultimately, I'm trying to determine if there's any area that needs deeper analysis or immediate attention.



12/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "config HWPOISON_INJECT"
}

Results:
{
  "Output": "mm/Kconfig=777=config MEMORY_FAILURE\n--\nmm/Kconfig-787-\nmm/Kconfig:788:config HWPOISON_INJECT\nmm/Kconfig-789-\ttristate \"HWPoison pages injector\"\n"
}

13/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11151
							output: 17
							thoughts: 46
						

Thoughts:
Here's my summary, as though I'm thinking through this process:

**Enabling Robust Hardware Poison Testing**

Okay, so I'm thinking, to really give the hardware poison logic a workout, I should definitely enable both `MEMORY_FAILURE` and `HWPOISON_INJECT`. That combination should provide a solid platform for testing. And, of course, I'll need `SWAP` enabled, since the `ttu_anon_swapbacked_folio` test relies on it. Makes sense. Need the basics to work on the specifics.



14/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "config SWAP"
}

Results:
{
  "Output": "arch/mips/Kconfig=1263=config MIPS_SPRAM\n--\narch/mips/Kconfig-1265-\narch/mips/Kconfig:1266:config SWAP_IO_SPACE\narch/mips/Kconfig-1267-\tbool\n--\narch/sh/Kconfig=129=config IO_TRAPPED\n--\narch/sh/Kconfig-131-\narch/sh/Kconfig:132:config SWAP_IO_SPACE\narch/sh/Kconfig-133-\tbool\n--\nmm/Kconfig=9=config ARCH_NO_SWAP\n--\nmm/Kconfig-11-\nmm/Kconfig:12:menuconfig SWAP\nmm/Kconfig-13-\tbool \"Support for paging of anonymous memory (swap)\"\n"
}

15/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11545
							output: 26
							thoughts: 226
						

Thoughts:
**Analyzing Unmapping Functions for Fuzzing Potential**

Okay, so the `SWAP` mechanism looks like a promising avenue for exploration. My initial thought is to identify the key functions related to memory unmapping, specifically within the context of hugetlbfs and anonymous pages, with the aim of potentially targeting them with fuzzing.

I need to nail down the core functions. Let's see... the ones that come to mind are: `try_to_unmap_hugetlb_one`, `ttu_anon_folio`, `ttu_anon_lazyfree_folio`, and `ttu_anon_swapbacked_folio`. All of those are static and nestled within `mm/rmap.c`, except for `try_to_unmap_hugetlb_one`, but a quick check reveals that it's also static. Hang on, isn't `try_to_unmap` exported? Yes, it is!

Now, the important question: Can Syzkaller effectively target *static* functions for fuzzing? My understanding is that while Syzkaller primarily targets syscalls, it uses function names for coverage guidance and potential control. These static functions are candidates for `FocusSymbols`, acting as useful filters or guides for the fuzzer. It looks like static functions are perfectly fine for this kind of guidance.

I should probably confirm by examining `try_to_unmap_hugetlb_one` in `mm/rmap.c` itself. Just to be sure.



16/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "try_to_unmap_hugetlb_one"
}

Results:
{
  "Output": "mm/rmap.c=1944=static inline unsigned int folio_unmap_pte_batch(struct folio *folio,\n--\nmm/rmap.c-1980-\nmm/rmap.c:1981:static bool try_to_unmap_hugetlb_one(struct folio *folio,\nmm/rmap.c-1982-\t\tstruct vm_area_struct *vma, unsigned long address, void *arg)\n--\nmm/rmap.c=2453=void try_to_unmap(struct folio *folio, enum ttu_flags flags)\n--\nmm/rmap.c-2456-\t\t.rmap_one = folio_test_hugetlb(folio) ?\nmm/rmap.c:2457:\t\t\t\ttry_to_unmap_hugetlb_one : try_to_unmap_one,\nmm/rmap.c-2458-\t\t.arg = (void *)flags,\n"
}

17/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12352
							output: 19
							thoughts: 19
						

Thoughts:
Okay, here's my summary, considering my expertise:

**My Initial Assessment and Next Steps**

Right, initial impression is that the situation is... well, *static*. Nothing's moving, nothing's dynamically changing, and that's not what I was expecting. Based on this, I need to investigate further. It's time to dive into the data. Specifically, I need to check out `ttu_anon_folio`. That's the logical next point of inquiry, given this initial static assessment. It should offer some specific details that either confirm the current state, or help to see what factors are causing this "still" state.



18/2 2026/07/07 20:38 tool grepper
0m Args:
{
  "Expression": "ttu_anon_folio"
}

Results:
{
  "Output": "mm/rmap.c=2140=static inline bool ttu_anon_swapbacked_folio(struct vm_area_struct *vma, struct folio *folio,\n--\nmm/rmap.c-2173-\nmm/rmap.c:2174:static inline bool ttu_anon_folio(struct vm_area_struct *vma, struct folio *folio,\nmm/rmap.c-2175-\t\tstruct page *subpage, unsigned long address, pte_t *ptep,\n--\nmm/rmap.c=2211=static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n--\nmm/rmap.c-2387-\t\t} else if (folio_test_anon(folio)) {\nmm/rmap.c:2388:\t\t\tif (!ttu_anon_folio(vma, folio, subpage, address,\nmm/rmap.c-2389-\t\t\t\t\t    pvmw.pte, pteval, nr_pages))\n"
}

19/2 2026/07/07 20:38 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12787
							output: 201
							thoughts: 428
						

Thoughts:
**Analyzing the Unmapping Logic Refactor**

Okay, so I'm looking at this patch and it's dealing with the unmapping logic in `mm/rmap.c`. The core of it seems to be extracting hugetlb and anonymous folio unmapping into specific functions. I need to make sure Syzkaller is focused on the right symbols to catch any regressions.

Right, the functions... Let's see. `try_to_unmap_hugetlb_one` is not inline, so it *should* appear as a symbol, easy. Then `ttu_anon_lazyfree_folio` and `ttu_anon_swapbacked_folio` are `static inline`. It's fine to include static inline functions, Syzkaller *can* handle those if we have debug info. Now, let me check the non-inline functions, `try_to_unmap` is global, which is also easy. `try_to_unmap_one` is static.

Alright, so my list of functions to include in `FocusSymbols` is going to be:
- `try_to_unmap_hugetlb_one`
- `ttu_anon_folio`
- `ttu_anon_lazyfree_folio`
- `ttu_anon_swapbacked_folio`
- `try_to_unmap_one`

That should cover the core changes related to the folio unmapping logic. The patch mentions reverse mapping, huge pages, and swap, so the fuzzing should target those areas.

Now, let's look at the configs that are relevant. I can see the patch uses `HUGETLBFS`, `SWAP`, `MEMORY_FAILURE`, and `HWPOISON_INJECT`. The new logic interacts with memory failure, and the hwpoison testing, and anonymous memory and hugetlb.

I need to make sure I get the memory failure logic covered in the fuzzing. The patch is also using `folio_test_hwpoison(folio)` so `TTU_HWPOISON` is going to be relevant. `folio_test_anon(folio)` for anonymous memory, and `folio_test_hugetlb(folio)` for hugetlb.

Okay, I think I've got it all. Time to call `set-results`.



20/2 2026/07/07 20:38 tool set-results
0m Args:
{
  "EnableConfigs": [
    "HUGETLBFS",
    "SWAP",
    "MEMORY_FAILURE",
    "HWPOISON_INJECT"
  ],
  "FocusSymbols": [
    "try_to_unmap_hugetlb_one",
    "ttu_anon_folio",
    "ttu_anon_lazyfree_folio",
    "ttu_anon_swapbacked_folio",
    "try_to_unmap_one"
  ],
  "Reasoning": "The patch refactors the unmapping logic in mm/rmap.c by extracting hugetlb and anonymous folio unmapping into separate functions (try_to_unmap_hugetlb_one, ttu_anon_folio, etc.). It modifies core memory management logic related to reverse mapping, huge pages, and swap. Fuzzing should focus on these new functions to ensure no regressions or bugs were introduced during the refactoring.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "HUGETLBFS",
    "SWAP",
    "MEMORY_FAILURE",
    "HWPOISON_INJECT"
  ],
  "FocusSymbols": [
    "try_to_unmap_hugetlb_one",
    "ttu_anon_folio",
    "ttu_anon_lazyfree_folio",
    "ttu_anon_swapbacked_folio",
    "try_to_unmap_one"
  ],
  "Reasoning": "The patch refactors the unmapping logic in mm/rmap.c by extracting hugetlb and anonymous folio unmapping into separate functions (try_to_unmap_hugetlb_one, ttu_anon_folio, etc.). It modifies core memory management logic related to reverse mapping, huge pages, and swap. Fuzzing should focus on these new functions to ensure no regressions or bugs were introduced during the refactoring.",
  "WorthFuzzing": true
}

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)