AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/01 00:11 flow patch-triage
3m Args:
null

Results:
{
  "EnableConfigs": [
    "TRANSPARENT_HUGEPAGE",
    "ZONE_DEVICE",
    "DEVICE_PRIVATE",
    "TEST_HMM"
  ],
  "FocusSymbols": [
    "pagemap_pmd_range_thp",
    "migrate_vma_collect_huge_pmd",
    "change_non_present_huge_pmd",
    "set_pmd_migration_entry",
    "remove_migration_pmd",
    "migrate_vma_insert_huge_pmd_page"
  ],
  "Reasoning": "The patch renames CONFIG_ARCH_ENABLE_THP_MIGRATION to CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF and introduces softleaf_to_pmd and softleaf_from_pmd to handle softleaf entries. It also fixes potential bugs where softleaf_to_page or softleaf_to_folio is called on entries without a PFN or non-device-private entries in fs/proc/task_mmu.c and mm/migrate_device.c. It also introduces mm_prepare_for_swap_entries to ensure mm is on init_mm.mmlist before adding swap entries. These are functional changes that affect memory management, THP migration, and device memory migration.",
  "WorthFuzzing": true
}

1/1 2026/07/01 00:11 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit e9dd1e00adf260034b58a73dca4c9a308d481bb1\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Jul 1 00:11:23 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig\nindex b3afe0688919bd..3eb94f36c77e88 100644\n--- a/arch/arm64/Kconfig\n+++ b/arch/arm64/Kconfig\n@@ -17,7 +17,7 @@ config ARM64\n \tselect ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE \u0026\u0026 MIGRATION\n \tselect ARCH_ENABLE_MEMORY_HOTPLUG\n \tselect ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS \u003e 2\n-\tselect ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE\n+\tselect ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE\n \tselect ARCH_HAS_CACHE_LINE_SIZE\n \tselect ARCH_HAS_CC_PLATFORM\n \tselect ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION\ndiff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h\nindex 27689c62bd25dd..984badfa9a74ab 100644\n--- a/arch/arm64/include/asm/pgtable.h\n+++ b/arch/arm64/include/asm/pgtable.h\n@@ -1534,10 +1534,10 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,\n #define __pte_to_swp_entry(pte)\t((swp_entry_t) { pte_val(pte) })\n #define __swp_entry_to_pte(swp)\t((pte_t) { (swp).val })\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n #define __pmd_to_swp_entry(pmd)\t\t((swp_entry_t) { pmd_val(pmd) })\n #define __swp_entry_to_pmd(swp)\t\t__pmd((swp).val)\n-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n /*\n  * Ensure that there are not more swap files than can be encoded in the kernel\ndiff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig\nindex d8d25232501791..550142b7ee102a 100644\n--- a/arch/loongarch/Kconfig\n+++ b/arch/loongarch/Kconfig\n@@ -12,7 +12,7 @@ config LOONGARCH\n \tselect ARCH_NEEDS_DEFER_KASAN\n \tselect ARCH_DISABLE_KASAN_INLINE\n \tselect ARCH_ENABLE_MEMORY_HOTPLUG\n-\tselect ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE\n+\tselect ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE\n \tselect ARCH_HAS_ACPI_TABLE_UPGRADE\tif ACPI\n \tselect ARCH_HAS_CPU_FINALIZE_INIT\n \tselect ARCH_HAS_CURRENT_STACK_POINTER\ndiff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h\nindex e67e64ac6e8cfc..6f30aa8a6490e1 100644\n--- a/arch/powerpc/include/asm/book3s/64/pgtable.h\n+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h\n@@ -1060,7 +1060,7 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)\n #define pmd_mksoft_dirty(pmd)  pte_pmd(pte_mksoft_dirty(pmd_pte(pmd)))\n #define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd)))\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n #define pmd_swp_mksoft_dirty(pmd)\tpte_pmd(pte_swp_mksoft_dirty(pmd_pte(pmd)))\n #define pmd_swp_soft_dirty(pmd)\t\tpte_swp_soft_dirty(pmd_pte(pmd))\n #define pmd_swp_clear_soft_dirty(pmd)\tpte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd)))\ndiff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype\nindex bac02c83bb3e4f..4a0fa681bf9814 100644\n--- a/arch/powerpc/platforms/Kconfig.cputype\n+++ b/arch/powerpc/platforms/Kconfig.cputype\n@@ -112,7 +112,7 @@ config PPC_THP\n        depends on PPC_RADIX_MMU || (PPC_64S_HASH_MMU \u0026\u0026 PAGE_SIZE_64KB)\n        select HAVE_ARCH_TRANSPARENT_HUGEPAGE\n        select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD\n-       select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE\n+       select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE\n \n choice\n \tprompt \"CPU selection\"\ndiff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig\nindex 3f0a647218e407..bf7b271cccd804 100644\n--- a/arch/riscv/Kconfig\n+++ b/arch/riscv/Kconfig\n@@ -22,7 +22,7 @@ config RISCV\n \tselect ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE \u0026\u0026 MIGRATION\n \tselect ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM_VMEMMAP\n \tselect ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS \u003e 2\n-\tselect ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE\n+\tselect ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE\n \tselect ARCH_HAS_BINFMT_FLAT\n \tselect ARCH_HAS_CC_CAN_LINK\n \tselect ARCH_HAS_CURRENT_STACK_POINTER\ndiff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h\nindex 5d5756bda82e3d..2aa529e882d304 100644\n--- a/arch/riscv/include/asm/pgtable.h\n+++ b/arch/riscv/include/asm/pgtable.h\n@@ -946,7 +946,7 @@ static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd)\n \treturn pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd)));\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n static inline bool pmd_swp_soft_dirty(pmd_t pmd)\n {\n \treturn pte_swp_soft_dirty(pmd_pte(pmd));\n@@ -961,7 +961,7 @@ static inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)\n {\n \treturn pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd)));\n }\n-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */\n \n static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,\n@@ -1208,10 +1208,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)\n \treturn __pte(pte_val(pte) \u0026 ~_PAGE_SWP_EXCLUSIVE);\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n #define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) })\n #define __swp_entry_to_pmd(swp) __pmd((swp).val)\n-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n /*\n  * In the RV64 Linux scheme, we give the user half of the virtual-address space\ndiff --git a/arch/s390/Kconfig b/arch/s390/Kconfig\nindex 84404e6778d504..0719f68de0f36f 100644\n--- a/arch/s390/Kconfig\n+++ b/arch/s390/Kconfig\n@@ -82,7 +82,7 @@ config S390\n \tselect ARCH_CORRECT_STACKTRACE_ON_KRETPROBE\n \tselect ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM\n \tselect ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS \u003e 2\n-\tselect ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE\n+\tselect ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE\n \tselect ARCH_HAS_CC_CAN_LINK\n \tselect ARCH_HAS_CPU_FINALIZE_INIT\n \tselect ARCH_HAS_CURRENT_STACK_POINTER\ndiff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h\nindex 859ce7c7d45448..6faccfa63b0933 100644\n--- a/arch/s390/include/asm/pgtable.h\n+++ b/arch/s390/include/asm/pgtable.h\n@@ -903,7 +903,7 @@ static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd)\n \treturn clear_pmd_bit(pmd, __pgprot(_SEGMENT_ENTRY_SOFT_DIRTY));\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n #define pmd_swp_soft_dirty(pmd)\t\tpmd_soft_dirty(pmd)\n #define pmd_swp_mksoft_dirty(pmd)\tpmd_mksoft_dirty(pmd)\n #define pmd_swp_clear_soft_dirty(pmd)\tpmd_clear_soft_dirty(pmd)\ndiff --git a/arch/x86/Kconfig b/arch/x86/Kconfig\nindex bdad90f210e4bf..50e00d8417aacc 100644\n--- a/arch/x86/Kconfig\n+++ b/arch/x86/Kconfig\n@@ -70,7 +70,7 @@ config X86\n \tselect ARCH_ENABLE_HUGEPAGE_MIGRATION if X86_64 \u0026\u0026 HUGETLB_PAGE \u0026\u0026 MIGRATION\n \tselect ARCH_ENABLE_MEMORY_HOTPLUG if X86_64\n \tselect ARCH_ENABLE_SPLIT_PMD_PTLOCK if (PGTABLE_LEVELS \u003e 2) \u0026\u0026 (X86_64 || X86_PAE)\n-\tselect ARCH_ENABLE_THP_MIGRATION if X86_64 \u0026\u0026 TRANSPARENT_HUGEPAGE\n+\tselect ARCH_SUPPORTS_PMD_SOFTLEAF if X86_64 \u0026\u0026 TRANSPARENT_HUGEPAGE\n \tselect ARCH_HAS_ACPI_TABLE_UPGRADE\tif ACPI\n \tselect ARCH_HAS_CPU_ATTACK_VECTORS\tif CPU_MITIGATIONS\n \tselect ARCH_HAS_CACHE_LINE_SIZE\ndiff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h\nindex ac295ca6c92f99..e0fd318d4004d1 100644\n--- a/arch/x86/include/asm/pgtable.h\n+++ b/arch/x86/include/asm/pgtable.h\n@@ -1545,7 +1545,7 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)\n \treturn pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n static inline pmd_t pmd_swp_mksoft_dirty(pmd_t pmd)\n {\n \treturn pmd_set_flags(pmd, _PAGE_SWP_SOFT_DIRTY);\ndiff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c\nindex d32408f7cd5ed2..1fb5acd88ad024 100644\n--- a/fs/proc/task_mmu.c\n+++ b/fs/proc/task_mmu.c\n@@ -2129,7 +2129,8 @@ static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,\n \t\t\tflags |= PM_SOFT_DIRTY;\n \t\tif (pmd_swp_uffd_wp(pmd))\n \t\t\tflags |= PM_UFFD_WP;\n-\t\tpage = softleaf_to_page(entry);\n+\t\tif (softleaf_has_pfn(entry))\n+\t\t\tpage = softleaf_to_page(entry);\n \t}\n \n \tif (page) {\ndiff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h\nindex ad20f7f8c17944..1487bf4af1a7ec 100644\n--- a/include/linux/huge_mm.h\n+++ b/include/linux/huge_mm.h\n@@ -567,7 +567,7 @@ static inline struct folio *get_persistent_huge_zero_folio(void)\n \n static inline bool thp_migration_supported(void)\n {\n-\treturn IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION);\n+\treturn IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF);\n }\n \n void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address,\ndiff --git a/include/linux/leafops.h b/include/linux/leafops.h\nindex 992cd8bd8ed0e9..88888daeb018a9 100644\n--- a/include/linux/leafops.h\n+++ b/include/linux/leafops.h\n@@ -81,7 +81,7 @@ static inline pte_t softleaf_to_pte(softleaf_t entry)\n \treturn swp_entry_to_pte(entry);\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n /**\n  * softleaf_from_pmd() - Obtain a leaf entry from a PMD entry.\n  * @pmd: PMD entry.\n@@ -108,6 +108,21 @@ static inline softleaf_t softleaf_from_pmd(pmd_t pmd)\n \treturn swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));\n }\n \n+/**\n+ * softleaf_to_pmd() - Obtain a PMD entry from a leaf entry.\n+ * @entry: Leaf entry.\n+ *\n+ * This generates an architecture-specific PMD entry that can be utilised to\n+ * encode the metadata the leaf entry encodes.\n+ *\n+ * Returns: Architecture-specific PMD entry encoding leaf entry.\n+ */\n+static inline pmd_t softleaf_to_pmd(softleaf_t entry)\n+{\n+\t/* Temporary until swp_entry_t eliminated. */\n+\treturn swp_entry_to_pmd(entry);\n+}\n+\n #else\n \n static inline softleaf_t softleaf_from_pmd(pmd_t pmd)\n@@ -115,6 +130,11 @@ static inline softleaf_t softleaf_from_pmd(pmd_t pmd)\n \treturn softleaf_mk_none();\n }\n \n+static inline pmd_t softleaf_to_pmd(softleaf_t entry)\n+{\n+\treturn __pmd(0);\n+}\n+\n #endif\n \n /**\n@@ -567,7 +587,7 @@ static inline bool pte_is_uffd_marker(pte_t pte)\n \treturn false;\n }\n \n-#if defined(CONFIG_ZONE_DEVICE) \u0026\u0026 defined(CONFIG_ARCH_ENABLE_THP_MIGRATION)\n+#if defined(CONFIG_ZONE_DEVICE) \u0026\u0026 defined(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF)\n \n /**\n  * pmd_is_device_private_entry() - Check if PMD contains a device private swap\n@@ -586,14 +606,14 @@ static inline bool pmd_is_device_private_entry(pmd_t pmd)\n \treturn softleaf_is_device_private(softleaf_from_pmd(pmd));\n }\n \n-#else  /* CONFIG_ZONE_DEVICE \u0026\u0026 CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#else  /* CONFIG_ZONE_DEVICE \u0026\u0026 CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n static inline bool pmd_is_device_private_entry(pmd_t pmd)\n {\n \treturn false;\n }\n \n-#endif /* CONFIG_ZONE_DEVICE \u0026\u0026 CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif /* CONFIG_ZONE_DEVICE \u0026\u0026 CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n /**\n  * pmd_is_migration_entry() - Does this PMD entry encode a migration entry?\ndiff --git a/include/linux/pgtable.h b/include/linux/pgtable.h\nindex d52d2a976e5a28..e38f069c1c9108 100644\n--- a/include/linux/pgtable.h\n+++ b/include/linux/pgtable.h\n@@ -1839,7 +1839,7 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)\n #endif\n \n #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY\n-#ifndef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifndef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n static inline pmd_t pmd_swp_mksoft_dirty(pmd_t pmd)\n {\n \treturn pmd;\ndiff --git a/include/linux/swapops.h b/include/linux/swapops.h\nindex 8cfc966eae48eb..705a84154d28eb 100644\n--- a/include/linux/swapops.h\n+++ b/include/linux/swapops.h\n@@ -321,7 +321,7 @@ static inline swp_entry_t make_guard_swp_entry(void)\n \n struct page_vma_mapped_walk;\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n extern int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n \t\tstruct page *page);\n \n@@ -338,7 +338,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)\n \treturn __swp_entry_to_pmd(arch_entry);\n }\n \n-#else  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#else  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n static inline int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n \t\tstruct page *page)\n {\n@@ -358,7 +358,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)\n \treturn __pmd(0);\n }\n \n-#endif  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n #endif /* CONFIG_MMU */\n #endif /* _LINUX_SWAPOPS_H */\ndiff --git a/mm/Kconfig b/mm/Kconfig\nindex 9e0ca48249054f..04fe5171bb8c80 100644\n--- a/mm/Kconfig\n+++ b/mm/Kconfig\n@@ -703,7 +703,7 @@ config DEVICE_MIGRATION\n config ARCH_ENABLE_HUGEPAGE_MIGRATION\n \tbool\n \n-config ARCH_ENABLE_THP_MIGRATION\n+config ARCH_SUPPORTS_PMD_SOFTLEAF\n \tbool\n \n config HUGETLB_PAGE_SIZE_VARIABLE\ndiff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c\nindex 23dc3ee0956192..507fbd1ae7e535 100644\n--- a/mm/debug_vm_pgtable.c\n+++ b/mm/debug_vm_pgtable.c\n@@ -751,14 +751,14 @@ static void __init pmd_leaf_soft_dirty_tests(struct pgtable_debug_args *args)\n \tpmd_t pmd;\n \n \tif (!pgtable_supports_soft_dirty() ||\n-\t    !IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION))\n+\t    !IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF))\n \t\treturn;\n \n \tif (!has_transparent_hugepage())\n \t\treturn;\n \n \tpr_debug(\"Validating PMD swap soft dirty\\n\");\n-\tpmd = swp_entry_to_pmd(args-\u003eleaf_entry);\n+\tpmd = softleaf_to_pmd(args-\u003eleaf_entry);\n \tWARN_ON(!pmd_is_huge(pmd));\n \tWARN_ON(!pmd_is_valid_softleaf(pmd));\n \n@@ -819,7 +819,7 @@ static void __init pte_swap_tests(struct pgtable_debug_args *args)\n \tWARN_ON(memcmp(\u0026pte1, \u0026pte2, sizeof(pte1)));\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)\n {\n \tswp_entry_t arch_entry;\n@@ -829,7 +829,7 @@ static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)\n \t\treturn;\n \n \tpr_debug(\"Validating PMD swap\\n\");\n-\tpmd1 = swp_entry_to_pmd(args-\u003eleaf_entry);\n+\tpmd1 = softleaf_to_pmd(args-\u003eleaf_entry);\n \tWARN_ON(!pmd_is_huge(pmd1));\n \tWARN_ON(!pmd_is_valid_softleaf(pmd1));\n \n@@ -837,9 +837,9 @@ static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)\n \tpmd2 = __swp_entry_to_pmd(arch_entry);\n \tWARN_ON(memcmp(\u0026pmd1, \u0026pmd2, sizeof(pmd1)));\n }\n-#else  /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#else  /* !CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n static void __init pmd_softleaf_tests(struct pgtable_debug_args *args) { }\n-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n static void __init swap_migration_tests(struct pgtable_debug_args *args)\n {\ndiff --git a/mm/hmm.c b/mm/hmm.c\nindex c72c9ddfdb2f62..4f3f627d2b4772 100644\n--- a/mm/hmm.c\n+++ b/mm/hmm.c\n@@ -331,7 +331,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,\n \treturn hmm_vma_fault(addr, end, required_fault, walk);\n }\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,\n \t\t\t\t     unsigned long end, unsigned long *hmm_pfns,\n \t\t\t\t     pmd_t pmd)\n@@ -391,7 +391,7 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,\n \t\treturn -EFAULT;\n \treturn hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);\n }\n-#endif  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#endif  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n \n static int hmm_vma_walk_pmd(pmd_t *pmdp,\n \t\t\t    unsigned long start,\ndiff --git a/mm/huge_memory.c b/mm/huge_memory.c\nindex 2bccb0a53a0a60..4b6e441ae931ec 100644\n--- a/mm/huge_memory.c\n+++ b/mm/huge_memory.c\n@@ -1819,7 +1819,7 @@ static void copy_huge_non_present_pmd(\n \tif (softleaf_is_migration_write(entry) ||\n \t    softleaf_is_migration_read_exclusive(entry)) {\n \t\tentry = make_readable_migration_entry(swp_offset(entry));\n-\t\tpmd = swp_entry_to_pmd(entry);\n+\t\tpmd = softleaf_to_pmd(entry);\n \t\tif (pmd_swp_soft_dirty(*src_pmd))\n \t\t\tpmd = pmd_swp_mksoft_dirty(pmd);\n \t\tif (pmd_swp_uffd_wp(*src_pmd))\n@@ -1832,7 +1832,7 @@ static void copy_huge_non_present_pmd(\n \t\t */\n \t\tif (softleaf_is_device_private_write(entry)) {\n \t\t\tentry = make_readable_device_private_entry(swp_offset(entry));\n-\t\t\tpmd = swp_entry_to_pmd(entry);\n+\t\t\tpmd = softleaf_to_pmd(entry);\n \n \t\t\tif (pmd_swp_soft_dirty(*src_pmd))\n \t\t\t\tpmd = pmd_swp_mksoft_dirty(pmd);\n@@ -2557,11 +2557,12 @@ static void change_non_present_huge_pmd(struct mm_struct *mm,\n \t\tbool uffd_wp_resolve)\n {\n \tsoftleaf_t entry = softleaf_from_pmd(*pmd);\n-\tconst struct folio *folio = softleaf_to_folio(entry);\n \tpmd_t newpmd;\n \n \tVM_WARN_ON(!pmd_is_valid_softleaf(*pmd));\n \tif (softleaf_is_migration_write(entry)) {\n+\t\tconst struct folio *folio = softleaf_to_folio(entry);\n+\n \t\t/*\n \t\t * A protection check is difficult so\n \t\t * just be safe and disable write\n@@ -2570,12 +2571,12 @@ static void change_non_present_huge_pmd(struct mm_struct *mm,\n \t\t\tentry = make_readable_exclusive_migration_entry(swp_offset(entry));\n \t\telse\n \t\t\tentry = make_readable_migration_entry(swp_offset(entry));\n-\t\tnewpmd = swp_entry_to_pmd(entry);\n+\t\tnewpmd = softleaf_to_pmd(entry);\n \t\tif (pmd_swp_soft_dirty(*pmd))\n \t\t\tnewpmd = pmd_swp_mksoft_dirty(newpmd);\n \t} else if (softleaf_is_device_private_write(entry)) {\n \t\tentry = make_readable_device_private_entry(swp_offset(entry));\n-\t\tnewpmd = swp_entry_to_pmd(entry);\n+\t\tnewpmd = softleaf_to_pmd(entry);\n \t\tif (pmd_swp_uffd_wp(*pmd))\n \t\t\tnewpmd = pmd_swp_mkuffd_wp(newpmd);\n \t} else {\n@@ -4863,7 +4864,7 @@ static int __init split_huge_pages_debugfs(void)\n late_initcall(split_huge_pages_debugfs);\n #endif\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n \t\tstruct page *page)\n {\n@@ -4923,7 +4924,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n \t}\n \n \t/* Set PMD. */\n-\tpmdswp = swp_entry_to_pmd(entry);\n+\tpmdswp = softleaf_to_pmd(entry);\n \tif (softdirty)\n \t\tpmdswp = pmd_swp_mksoft_dirty(pmdswp);\n \tif (uffd_wp)\n@@ -4976,7 +4977,7 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)\n \t\telse\n \t\t\tentry = make_readable_device_private_entry(\n \t\t\t\t\t\t\tpage_to_pfn(new));\n-\t\tpmde = swp_entry_to_pmd(entry);\n+\t\tpmde = softleaf_to_pmd(entry);\n \n \t\tif (pmd_swp_soft_dirty(*pvmw-\u003epmd))\n \t\t\tpmde = pmd_swp_mksoft_dirty(pmde);\ndiff --git a/mm/internal.h b/mm/internal.h\nindex 8e0df3d1c6f980..0e3db9451e5c78 100644\n--- a/mm/internal.h\n+++ b/mm/internal.h\n@@ -1956,4 +1956,17 @@ static inline int get_sysctl_max_map_count(void)\n bool may_expand_vm(struct mm_struct *mm, const vma_flags_t *vma_flags,\n \t\t   unsigned long npages);\n \n+/*\n+ * Ensure @mm is on the init_mm.mmlist so swapoff can find it.\n+ */\n+static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)\n+{\n+\tif (list_empty(\u0026mm-\u003emmlist)) {\n+\t\tspin_lock(\u0026mmlist_lock);\n+\t\tif (list_empty(\u0026mm-\u003emmlist))\n+\t\t\tlist_add(\u0026mm-\u003emmlist, \u0026init_mm.mmlist);\n+\t\tspin_unlock(\u0026mmlist_lock);\n+\t}\n+}\n+\n #endif\t/* __MM_INTERNAL_H */\ndiff --git a/mm/memory.c b/mm/memory.c\nindex a3fcaf8cfe8f8b..6637c5b13c9bac 100644\n--- a/mm/memory.c\n+++ b/mm/memory.c\n@@ -953,14 +953,7 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,\n \t\tif (swap_dup_entry_direct(entry) \u003c 0)\n \t\t\treturn -EIO;\n \n-\t\t/* make sure dst_mm is on swapoff's mmlist. */\n-\t\tif (unlikely(list_empty(\u0026dst_mm-\u003emmlist))) {\n-\t\t\tspin_lock(\u0026mmlist_lock);\n-\t\t\tif (list_empty(\u0026dst_mm-\u003emmlist))\n-\t\t\t\tlist_add(\u0026dst_mm-\u003emmlist,\n-\t\t\t\t\t\t\u0026src_mm-\u003emmlist);\n-\t\t\tspin_unlock(\u0026mmlist_lock);\n-\t\t}\n+\t\tmm_prepare_for_swap_entries(dst_mm);\n \t\t/* Mark the swap entry as shared. */\n \t\tif (pte_swp_exclusive(orig_pte)) {\n \t\t\tpte = pte_swp_clear_exclusive(orig_pte);\ndiff --git a/mm/migrate.c b/mm/migrate.c\nindex 49e10feeb094f0..c48dc5127e6aa9 100644\n--- a/mm/migrate.c\n+++ b/mm/migrate.c\n@@ -362,7 +362,7 @@ static bool remove_migration_pte(struct folio *folio,\n \t\t\tidx = linear_page_index(vma, pvmw.address) - pvmw.pgoff;\n \t\tnew = folio_page(folio, idx);\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n \t\t/* PMD-mapped THP migration entry */\n \t\tif (!pvmw.pte) {\n \t\t\tVM_BUG_ON_FOLIO(folio_test_hugetlb(folio) ||\n@@ -545,7 +545,7 @@ void migration_entry_wait_huge(struct vm_area_struct *vma, unsigned long addr, p\n }\n #endif\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n void pmd_migration_entry_wait(struct mm_struct *mm, pmd_t *pmd)\n {\n \tspinlock_t *ptl;\ndiff --git a/mm/migrate_device.c b/mm/migrate_device.c\nindex ae39173d6a0e8a..2f8b646302c251 100644\n--- a/mm/migrate_device.c\n+++ b/mm/migrate_device.c\n@@ -166,11 +166,14 @@ static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,\n \t} else if (!pmd_present(*pmdp)) {\n \t\tconst softleaf_t entry = softleaf_from_pmd(*pmdp);\n \n-\t\tfolio = softleaf_to_folio(entry);\n-\n \t\tif (!softleaf_is_device_private(entry) ||\n-\t\t\t!(migrate-\u003eflags \u0026 MIGRATE_VMA_SELECT_DEVICE_PRIVATE) ||\n-\t\t\t(folio-\u003epgmap-\u003eowner != migrate-\u003epgmap_owner)) {\n+\t\t    !(migrate-\u003eflags \u0026 MIGRATE_VMA_SELECT_DEVICE_PRIVATE)) {\n+\t\t\tspin_unlock(ptl);\n+\t\t\treturn migrate_vma_collect_skip(start, end, walk);\n+\t\t}\n+\n+\t\tfolio = softleaf_to_folio(entry);\n+\t\tif (folio-\u003epgmap-\u003eowner != migrate-\u003epgmap_owner) {\n \t\t\tspin_unlock(ptl);\n \t\t\treturn migrate_vma_collect_skip(start, end, walk);\n \t\t}\n@@ -768,7 +771,7 @@ int migrate_vma_setup(struct migrate_vma *args)\n }\n EXPORT_SYMBOL(migrate_vma_setup);\n \n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n /**\n  * migrate_vma_insert_huge_pmd_page: Insert a huge folio into @migrate-\u003evma-\u003evm_mm\n  * at @addr. folio is already allocated as a part of the migration process with\n@@ -835,7 +838,7 @@ static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,\n \t\telse\n \t\t\tswp_entry = make_readable_device_private_entry(\n \t\t\t\t\t\tpage_to_pfn(page));\n-\t\tentry = swp_entry_to_pmd(swp_entry);\n+\t\tentry = softleaf_to_pmd(swp_entry);\n \t} else {\n \t\tif (folio_is_zone_device(folio) \u0026\u0026\n \t\t    !folio_is_device_coherent(folio)) {\n@@ -923,7 +926,7 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,\n \t\tmigrate-\u003esrc[i+idx] = migrate_pfn(pfn + i) | flags;\n \treturn ret;\n }\n-#else /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */\n+#else /* !CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\n static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,\n \t\t\t\t\t unsigned long addr,\n \t\t\t\t\t struct page *page,\n@@ -944,7 +947,7 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,\n static unsigned long migrate_vma_nr_pages(unsigned long *src)\n {\n \tunsigned long nr = 1;\n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n \tif (*src \u0026 MIGRATE_PFN_COMPOUND)\n \t\tnr = HPAGE_PMD_NR;\n #else\ndiff --git a/mm/rmap.c b/mm/rmap.c\nindex 1c77d5dc06e9fa..0fb7a1b82cf3c2 100644\n--- a/mm/rmap.c\n+++ b/mm/rmap.c\n@@ -2304,12 +2304,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\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\tif (list_empty(\u0026mm-\u003emmlist)) {\n-\t\t\t\tspin_lock(\u0026mmlist_lock);\n-\t\t\t\tif (list_empty(\u0026mm-\u003emmlist))\n-\t\t\t\t\tlist_add(\u0026mm-\u003emmlist, \u0026init_mm.mmlist);\n-\t\t\t\tspin_unlock(\u0026mmlist_lock);\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@@ -2477,7 +2472,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n \t\t\t\tpage_vma_mapped_walk_restart(\u0026pvmw);\n \t\t\t\tcontinue;\n \t\t\t}\n-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\n \t\t\tpmdval = pmdp_get(pvmw.pmd);\n \t\t\tif (likely(pmd_present(pmdval)))\n \t\t\t\tpfn = pmd_pfn(pmdval);\n"
}

2/1 2026/07/01 00:11 agent patch-evaluator
3m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "TRANSPARENT_HUGEPAGE",
    "ZONE_DEVICE",
    "DEVICE_PRIVATE",
    "TEST_HMM"
  ],
  "FocusSymbols": [
    "pagemap_pmd_range_thp",
    "migrate_vma_collect_huge_pmd",
    "change_non_present_huge_pmd",
    "set_pmd_migration_entry",
    "remove_migration_pmd",
    "migrate_vma_insert_huge_pmd_page"
  ],
  "Reasoning": "The patch renames CONFIG_ARCH_ENABLE_THP_MIGRATION to CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF and introduces softleaf_to_pmd and softleaf_from_pmd to handle softleaf entries. It also fixes potential bugs where softleaf_to_page or softleaf_to_folio is called on entries without a PFN or non-device-private entries in fs/proc/task_mmu.c and mm/migrate_device.c. It also introduces mm_prepare_for_swap_entries to ensure mm is on init_mm.mmlist before adding swap entries. These are functional changes that affect memory management, THP migration, and device memory migration.",
  "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 e9dd1e00adf260034b58a73dca4c9a308d481bb1
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Jul 1 00:11:23 2026 +0000

    syz-cluster: applied patch under review

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919bd..3eb94f36c77e88 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -17,7 +17,7 @@ config ARM64
 	select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION
 	select ARCH_ENABLE_MEMORY_HOTPLUG
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
-	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+	select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_CACHE_LINE_SIZE
 	select ARCH_HAS_CC_PLATFORM
 	select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 27689c62bd25dd..984badfa9a74ab 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1534,10 +1534,10 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(swp)	((pte_t) { (swp).val })
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 #define __pmd_to_swp_entry(pmd)		((swp_entry_t) { pmd_val(pmd) })
 #define __swp_entry_to_pmd(swp)		__pmd((swp).val)
-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 /*
  * Ensure that there are not more swap files than can be encoded in the kernel
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index d8d25232501791..550142b7ee102a 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -12,7 +12,7 @@ config LOONGARCH
 	select ARCH_NEEDS_DEFER_KASAN
 	select ARCH_DISABLE_KASAN_INLINE
 	select ARCH_ENABLE_MEMORY_HOTPLUG
-	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+	select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_ACPI_TABLE_UPGRADE	if ACPI
 	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_CURRENT_STACK_POINTER
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index e67e64ac6e8cfc..6f30aa8a6490e1 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1060,7 +1060,7 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)
 #define pmd_mksoft_dirty(pmd)  pte_pmd(pte_mksoft_dirty(pmd_pte(pmd)))
 #define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd)))
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 #define pmd_swp_mksoft_dirty(pmd)	pte_pmd(pte_swp_mksoft_dirty(pmd_pte(pmd)))
 #define pmd_swp_soft_dirty(pmd)		pte_swp_soft_dirty(pmd_pte(pmd))
 #define pmd_swp_clear_soft_dirty(pmd)	pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd)))
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index bac02c83bb3e4f..4a0fa681bf9814 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -112,7 +112,7 @@ config PPC_THP
        depends on PPC_RADIX_MMU || (PPC_64S_HASH_MMU && PAGE_SIZE_64KB)
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-       select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+       select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE
 
 choice
 	prompt "CPU selection"
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 3f0a647218e407..bf7b271cccd804 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -22,7 +22,7 @@ config RISCV
 	select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION
 	select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM_VMEMMAP
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
-	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+	select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_BINFMT_FLAT
 	select ARCH_HAS_CC_CAN_LINK
 	select ARCH_HAS_CURRENT_STACK_POINTER
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 5d5756bda82e3d..2aa529e882d304 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -946,7 +946,7 @@ static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd)
 	return pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd)));
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 static inline bool pmd_swp_soft_dirty(pmd_t pmd)
 {
 	return pte_swp_soft_dirty(pmd_pte(pmd));
@@ -961,7 +961,7 @@ static inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)
 {
 	return pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd)));
 }
-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
 
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
@@ -1208,10 +1208,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 	return __pte(pte_val(pte) & ~_PAGE_SWP_EXCLUSIVE);
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 #define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) })
 #define __swp_entry_to_pmd(swp) __pmd((swp).val)
-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 /*
  * In the RV64 Linux scheme, we give the user half of the virtual-address space
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 84404e6778d504..0719f68de0f36f 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -82,7 +82,7 @@ config S390
 	select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
 	select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
-	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+	select ARCH_SUPPORTS_PMD_SOFTLEAF if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_CC_CAN_LINK
 	select ARCH_HAS_CPU_FINALIZE_INIT
 	select ARCH_HAS_CURRENT_STACK_POINTER
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 859ce7c7d45448..6faccfa63b0933 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -903,7 +903,7 @@ static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd)
 	return clear_pmd_bit(pmd, __pgprot(_SEGMENT_ENTRY_SOFT_DIRTY));
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 #define pmd_swp_soft_dirty(pmd)		pmd_soft_dirty(pmd)
 #define pmd_swp_mksoft_dirty(pmd)	pmd_mksoft_dirty(pmd)
 #define pmd_swp_clear_soft_dirty(pmd)	pmd_clear_soft_dirty(pmd)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bdad90f210e4bf..50e00d8417aacc 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -70,7 +70,7 @@ config X86
 	select ARCH_ENABLE_HUGEPAGE_MIGRATION if X86_64 && HUGETLB_PAGE && MIGRATION
 	select ARCH_ENABLE_MEMORY_HOTPLUG if X86_64
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if (PGTABLE_LEVELS > 2) && (X86_64 || X86_PAE)
-	select ARCH_ENABLE_THP_MIGRATION if X86_64 && TRANSPARENT_HUGEPAGE
+	select ARCH_SUPPORTS_PMD_SOFTLEAF if X86_64 && TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_ACPI_TABLE_UPGRADE	if ACPI
 	select ARCH_HAS_CPU_ATTACK_VECTORS	if CPU_MITIGATIONS
 	select ARCH_HAS_CACHE_LINE_SIZE
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index ac295ca6c92f99..e0fd318d4004d1 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1545,7 +1545,7 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
 	return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 static inline pmd_t pmd_swp_mksoft_dirty(pmd_t pmd)
 {
 	return pmd_set_flags(pmd, _PAGE_SWP_SOFT_DIRTY);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index d32408f7cd5ed2..1fb5acd88ad024 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2129,7 +2129,8 @@ static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,
 			flags |= PM_SOFT_DIRTY;
 		if (pmd_swp_uffd_wp(pmd))
 			flags |= PM_UFFD_WP;
-		page = softleaf_to_page(entry);
+		if (softleaf_has_pfn(entry))
+			page = softleaf_to_page(entry);
 	}
 
 	if (page) {
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index ad20f7f8c17944..1487bf4af1a7ec 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -567,7 +567,7 @@ static inline struct folio *get_persistent_huge_zero_folio(void)
 
 static inline bool thp_migration_supported(void)
 {
-	return IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION);
+	return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF);
 }
 
 void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address,
diff --git a/include/linux/leafops.h b/include/linux/leafops.h
index 992cd8bd8ed0e9..88888daeb018a9 100644
--- a/include/linux/leafops.h
+++ b/include/linux/leafops.h
@@ -81,7 +81,7 @@ static inline pte_t softleaf_to_pte(softleaf_t entry)
 	return swp_entry_to_pte(entry);
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 /**
  * softleaf_from_pmd() - Obtain a leaf entry from a PMD entry.
  * @pmd: PMD entry.
@@ -108,6 +108,21 @@ static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
 	return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
 }
 
+/**
+ * softleaf_to_pmd() - Obtain a PMD entry from a leaf entry.
+ * @entry: Leaf entry.
+ *
+ * This generates an architecture-specific PMD entry that can be utilised to
+ * encode the metadata the leaf entry encodes.
+ *
+ * Returns: Architecture-specific PMD entry encoding leaf entry.
+ */
+static inline pmd_t softleaf_to_pmd(softleaf_t entry)
+{
+	/* Temporary until swp_entry_t eliminated. */
+	return swp_entry_to_pmd(entry);
+}
+
 #else
 
 static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
@@ -115,6 +130,11 @@ static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
 	return softleaf_mk_none();
 }
 
+static inline pmd_t softleaf_to_pmd(softleaf_t entry)
+{
+	return __pmd(0);
+}
+
 #endif
 
 /**
@@ -567,7 +587,7 @@ static inline bool pte_is_uffd_marker(pte_t pte)
 	return false;
 }
 
-#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_ARCH_ENABLE_THP_MIGRATION)
+#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF)
 
 /**
  * pmd_is_device_private_entry() - Check if PMD contains a device private swap
@@ -586,14 +606,14 @@ static inline bool pmd_is_device_private_entry(pmd_t pmd)
 	return softleaf_is_device_private(softleaf_from_pmd(pmd));
 }
 
-#else  /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#else  /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 static inline bool pmd_is_device_private_entry(pmd_t pmd)
 {
 	return false;
 }
 
-#endif /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 /**
  * pmd_is_migration_entry() - Does this PMD entry encode a migration entry?
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index d52d2a976e5a28..e38f069c1c9108 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -1839,7 +1839,7 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
 #endif
 
 #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY
-#ifndef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifndef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 static inline pmd_t pmd_swp_mksoft_dirty(pmd_t pmd)
 {
 	return pmd;
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 8cfc966eae48eb..705a84154d28eb 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -321,7 +321,7 @@ static inline swp_entry_t make_guard_swp_entry(void)
 
 struct page_vma_mapped_walk;
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 extern int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
 		struct page *page);
 
@@ -338,7 +338,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)
 	return __swp_entry_to_pmd(arch_entry);
 }
 
-#else  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#else  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 static inline int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
 		struct page *page)
 {
@@ -358,7 +358,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)
 	return __pmd(0);
 }
 
-#endif  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 #endif /* CONFIG_MMU */
 #endif /* _LINUX_SWAPOPS_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index 9e0ca48249054f..04fe5171bb8c80 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -703,7 +703,7 @@ config DEVICE_MIGRATION
 config ARCH_ENABLE_HUGEPAGE_MIGRATION
 	bool
 
-config ARCH_ENABLE_THP_MIGRATION
+config ARCH_SUPPORTS_PMD_SOFTLEAF
 	bool
 
 config HUGETLB_PAGE_SIZE_VARIABLE
diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 23dc3ee0956192..507fbd1ae7e535 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -751,14 +751,14 @@ static void __init pmd_leaf_soft_dirty_tests(struct pgtable_debug_args *args)
 	pmd_t pmd;
 
 	if (!pgtable_supports_soft_dirty() ||
-	    !IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION))
+	    !IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF))
 		return;
 
 	if (!has_transparent_hugepage())
 		return;
 
 	pr_debug("Validating PMD swap soft dirty\n");
-	pmd = swp_entry_to_pmd(args->leaf_entry);
+	pmd = softleaf_to_pmd(args->leaf_entry);
 	WARN_ON(!pmd_is_huge(pmd));
 	WARN_ON(!pmd_is_valid_softleaf(pmd));
 
@@ -819,7 +819,7 @@ static void __init pte_swap_tests(struct pgtable_debug_args *args)
 	WARN_ON(memcmp(&pte1, &pte2, sizeof(pte1)));
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)
 {
 	swp_entry_t arch_entry;
@@ -829,7 +829,7 @@ static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)
 		return;
 
 	pr_debug("Validating PMD swap\n");
-	pmd1 = swp_entry_to_pmd(args->leaf_entry);
+	pmd1 = softleaf_to_pmd(args->leaf_entry);
 	WARN_ON(!pmd_is_huge(pmd1));
 	WARN_ON(!pmd_is_valid_softleaf(pmd1));
 
@@ -837,9 +837,9 @@ static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)
 	pmd2 = __swp_entry_to_pmd(arch_entry);
 	WARN_ON(memcmp(&pmd1, &pmd2, sizeof(pmd1)));
 }
-#else  /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#else  /* !CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 static void __init pmd_softleaf_tests(struct pgtable_debug_args *args) { }
-#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 static void __init swap_migration_tests(struct pgtable_debug_args *args)
 {
diff --git a/mm/hmm.c b/mm/hmm.c
index c72c9ddfdb2f62..4f3f627d2b4772 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -331,7 +331,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
 	return hmm_vma_fault(addr, end, required_fault, walk);
 }
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
 				     unsigned long end, unsigned long *hmm_pfns,
 				     pmd_t pmd)
@@ -391,7 +391,7 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
 		return -EFAULT;
 	return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR);
 }
-#endif  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#endif  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 
 static int hmm_vma_walk_pmd(pmd_t *pmdp,
 			    unsigned long start,
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2bccb0a53a0a60..4b6e441ae931ec 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1819,7 +1819,7 @@ static void copy_huge_non_present_pmd(
 	if (softleaf_is_migration_write(entry) ||
 	    softleaf_is_migration_read_exclusive(entry)) {
 		entry = make_readable_migration_entry(swp_offset(entry));
-		pmd = swp_entry_to_pmd(entry);
+		pmd = softleaf_to_pmd(entry);
 		if (pmd_swp_soft_dirty(*src_pmd))
 			pmd = pmd_swp_mksoft_dirty(pmd);
 		if (pmd_swp_uffd_wp(*src_pmd))
@@ -1832,7 +1832,7 @@ static void copy_huge_non_present_pmd(
 		 */
 		if (softleaf_is_device_private_write(entry)) {
 			entry = make_readable_device_private_entry(swp_offset(entry));
-			pmd = swp_entry_to_pmd(entry);
+			pmd = softleaf_to_pmd(entry);
 
 			if (pmd_swp_soft_dirty(*src_pmd))
 				pmd = pmd_swp_mksoft_dirty(pmd);
@@ -2557,11 +2557,12 @@ static void change_non_present_huge_pmd(struct mm_struct *mm,
 		bool uffd_wp_resolve)
 {
 	softleaf_t entry = softleaf_from_pmd(*pmd);
-	const struct folio *folio = softleaf_to_folio(entry);
 	pmd_t newpmd;
 
 	VM_WARN_ON(!pmd_is_valid_softleaf(*pmd));
 	if (softleaf_is_migration_write(entry)) {
+		const struct folio *folio = softleaf_to_folio(entry);
+
 		/*
 		 * A protection check is difficult so
 		 * just be safe and disable write
@@ -2570,12 +2571,12 @@ static void change_non_present_huge_pmd(struct mm_struct *mm,
 			entry = make_readable_exclusive_migration_entry(swp_offset(entry));
 		else
 			entry = make_readable_migration_entry(swp_offset(entry));
-		newpmd = swp_entry_to_pmd(entry);
+		newpmd = softleaf_to_pmd(entry);
 		if (pmd_swp_soft_dirty(*pmd))
 			newpmd = pmd_swp_mksoft_dirty(newpmd);
 	} else if (softleaf_is_device_private_write(entry)) {
 		entry = make_readable_device_private_entry(swp_offset(entry));
-		newpmd = swp_entry_to_pmd(entry);
+		newpmd = softleaf_to_pmd(entry);
 		if (pmd_swp_uffd_wp(*pmd))
 			newpmd = pmd_swp_mkuffd_wp(newpmd);
 	} else {
@@ -4863,7 +4864,7 @@ static int __init split_huge_pages_debugfs(void)
 late_initcall(split_huge_pages_debugfs);
 #endif
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
 		struct page *page)
 {
@@ -4923,7 +4924,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
 	}
 
 	/* Set PMD. */
-	pmdswp = swp_entry_to_pmd(entry);
+	pmdswp = softleaf_to_pmd(entry);
 	if (softdirty)
 		pmdswp = pmd_swp_mksoft_dirty(pmdswp);
 	if (uffd_wp)
@@ -4976,7 +4977,7 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)
 		else
 			entry = make_readable_device_private_entry(
 							page_to_pfn(new));
-		pmde = swp_entry_to_pmd(entry);
+		pmde = softleaf_to_pmd(entry);
 
 		if (pmd_swp_soft_dirty(*pvmw->pmd))
 			pmde = pmd_swp_mksoft_dirty(pmde);
diff --git a/mm/internal.h b/mm/internal.h
index 8e0df3d1c6f980..0e3db9451e5c78 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1956,4 +1956,17 @@ static inline int get_sysctl_max_map_count(void)
 bool may_expand_vm(struct mm_struct *mm, const vma_flags_t *vma_flags,
 		   unsigned long npages);
 
+/*
+ * Ensure @mm is on the init_mm.mmlist so swapoff can find it.
+ */
+static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)
+{
+	if (list_empty(&mm->mmlist)) {
+		spin_lock(&mmlist_lock);
+		if (list_empty(&mm->mmlist))
+			list_add(&mm->mmlist, &init_mm.mmlist);
+		spin_unlock(&mmlist_lock);
+	}
+}
+
 #endif	/* __MM_INTERNAL_H */
diff --git a/mm/memory.c b/mm/memory.c
index a3fcaf8cfe8f8b..6637c5b13c9bac 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -953,14 +953,7 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		if (swap_dup_entry_direct(entry) < 0)
 			return -EIO;
 
-		/* make sure dst_mm is on swapoff's mmlist. */
-		if (unlikely(list_empty(&dst_mm->mmlist))) {
-			spin_lock(&mmlist_lock);
-			if (list_empty(&dst_mm->mmlist))
-				list_add(&dst_mm->mmlist,
-						&src_mm->mmlist);
-			spin_unlock(&mmlist_lock);
-		}
+		mm_prepare_for_swap_entries(dst_mm);
 		/* Mark the swap entry as shared. */
 		if (pte_swp_exclusive(orig_pte)) {
 			pte = pte_swp_clear_exclusive(orig_pte);
diff --git a/mm/migrate.c b/mm/migrate.c
index 49e10feeb094f0..c48dc5127e6aa9 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -362,7 +362,7 @@ static bool remove_migration_pte(struct folio *folio,
 			idx = linear_page_index(vma, pvmw.address) - pvmw.pgoff;
 		new = folio_page(folio, idx);
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 		/* PMD-mapped THP migration entry */
 		if (!pvmw.pte) {
 			VM_BUG_ON_FOLIO(folio_test_hugetlb(folio) ||
@@ -545,7 +545,7 @@ void migration_entry_wait_huge(struct vm_area_struct *vma, unsigned long addr, p
 }
 #endif
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 void pmd_migration_entry_wait(struct mm_struct *mm, pmd_t *pmd)
 {
 	spinlock_t *ptl;
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index ae39173d6a0e8a..2f8b646302c251 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -166,11 +166,14 @@ static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,
 	} else if (!pmd_present(*pmdp)) {
 		const softleaf_t entry = softleaf_from_pmd(*pmdp);
 
-		folio = softleaf_to_folio(entry);
-
 		if (!softleaf_is_device_private(entry) ||
-			!(migrate->flags & MIGRATE_VMA_SELECT_DEVICE_PRIVATE) ||
-			(folio->pgmap->owner != migrate->pgmap_owner)) {
+		    !(migrate->flags & MIGRATE_VMA_SELECT_DEVICE_PRIVATE)) {
+			spin_unlock(ptl);
+			return migrate_vma_collect_skip(start, end, walk);
+		}
+
+		folio = softleaf_to_folio(entry);
+		if (folio->pgmap->owner != migrate->pgmap_owner) {
 			spin_unlock(ptl);
 			return migrate_vma_collect_skip(start, end, walk);
 		}
@@ -768,7 +771,7 @@ int migrate_vma_setup(struct migrate_vma *args)
 }
 EXPORT_SYMBOL(migrate_vma_setup);
 
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 /**
  * migrate_vma_insert_huge_pmd_page: Insert a huge folio into @migrate->vma->vm_mm
  * at @addr. folio is already allocated as a part of the migration process with
@@ -835,7 +838,7 @@ static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,
 		else
 			swp_entry = make_readable_device_private_entry(
 						page_to_pfn(page));
-		entry = swp_entry_to_pmd(swp_entry);
+		entry = softleaf_to_pmd(swp_entry);
 	} else {
 		if (folio_is_zone_device(folio) &&
 		    !folio_is_device_coherent(folio)) {
@@ -923,7 +926,7 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,
 		migrate->src[i+idx] = migrate_pfn(pfn + i) | flags;
 	return ret;
 }
-#else /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */
+#else /* !CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */
 static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,
 					 unsigned long addr,
 					 struct page *page,
@@ -944,7 +947,7 @@ static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,
 static unsigned long migrate_vma_nr_pages(unsigned long *src)
 {
 	unsigned long nr = 1;
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 	if (*src & MIGRATE_PFN_COMPOUND)
 		nr = HPAGE_PMD_NR;
 #else
diff --git a/mm/rmap.c b/mm/rmap.c
index 1c77d5dc06e9fa..0fb7a1b82cf3c2 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -2304,12 +2304,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 				set_pte_at(mm, address, pvmw.pte, pteval);
 				goto walk_abort;
 			}
-			if (list_empty(&mm->mmlist)) {
-				spin_lock(&mmlist_lock);
-				if (list_empty(&mm->mmlist))
-					list_add(&mm->mmlist, &init_mm.mmlist);
-				spin_unlock(&mmlist_lock);
-			}
+			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);
@@ -2477,7 +2472,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
 				page_vma_mapped_walk_restart(&pvmw);
 				continue;
 			}
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF
 			pmdval = pmdp_get(pvmw.pmd);
 			if (likely(pmd_present(pmdval)))
 				pfn = pmd_pfn(pmdval);

3/2 2026/07/01 00:11 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12006
							output: 19
							thoughts: 832
						

Thoughts:
**Analyzing the Proposed Softleaf Patch**

Okay, so I'm looking at this patch. It seems like a refactoring and bug-fixing effort related to softleaf handling, specifically around the new `CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF` feature. The patch renames `CONFIG_ARCH_ENABLE_THP_MIGRATION`, which indicates a significant architectural change. I see the introduction of functions like `softleaf_to_pmd`, `softleaf_from_pmd`, `softleaf_has_pfn`, `softleaf_is_device_private`, and `mm_prepare_for_swap_entries`. Let's break down the implications.

First, I examined the code changes. The adjustments in `fs/proc/task_mmu.c` and `mm/migrate_device.c` are definitely functional improvements. They're adding checks (`softleaf_has_pfn` and `softleaf_is_device_private` respectively) before calling `softleaf_to_page` and `softleaf_to_folio`. This is crucial; it prevents potential crashes or invalid memory accesses by handling cases where these conversions might be invalid, such as when dealing with swap entries. Good catch.

However, the changes in `mm/huge_memory.c` raise a concern. The code now retrieves the `folio` inside an `if` statement, after checking `softleaf_is_migration_write`. Previously, `folio` was obtained before this check. That’s a subtle but important change. I need to understand the impact of this code movement. It seems likely that the code now has a new branch to prevent an error.

Overall, these changes are addressing potential vulnerabilities. The patch is clearly attempting to fix scenarios where `softleaf_to_folio` or `softleaf_to_page` could be invoked on an inappropriate entry. That makes me feel confident about the functionality.

Now, let's consider the configuration requirements. `CONFIG_TRANSPARENT_HUGEPAGE` is essential since `ARCH_SUPPORTS_PMD_SOFTLEAF` depends on it. For the modifications in `mm/migrate_device.c`, it looks like `CONFIG_DEVICE_PRIVATE` or perhaps `CONFIG_DEVICE_MIGRATION` might be required. I should investigate that dependency more thoroughly to confirm the complete set of necessary configs.



4/2 2026/07/01 00:11 tool grepper
0m Args:
{
  "Expression": "migrate_device.o"
}

Results:
{
  "Output": "mm/Makefile=99=obj-$(CONFIG_NUMA) += memory-tiers.o\nmm/Makefile:100:obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o\nmm/Makefile-101-obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o\n"
}

5/2 2026/07/01 00:11 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13461
							output: 20
							thoughts: 39
						

Thoughts:
Okay, here's my take on those thoughts, framed from my perspective as a system expert:

**Investigating Device Migration Dependencies**

Alright, so I see that `CONFIG_DEVICE_MIGRATION` is essential for the `migrate_device.c` module to function. I already knew that, but it's good to be reminded. Now, I need to understand the full scope of how this interacts with the system.

My next step is to examine the dependencies of `fs/proc/task_mmu.c`. I need to understand if `migrate_device.c` has any connection to this area, as I'm interested in how device migration interacts with task and memory management, specifically within the procfs framework. The goal is to avoid any surprises, and to see if there are any subtle interactions to be aware of between device migration and task memory management. I suspect it might be relevant, given the nature of device migration. Let's dig in and see what `task_mmu.c` reveals.



6/2 2026/07/01 00:11 tool grepper
0m Args:
{
  "Expression": "task_mmu.o"
}

Results:
{
  "Output": "fs/proc/Makefile=6=obj-y   += proc.o\nfs/proc/Makefile-7-\nfs/proc/Makefile:8:CFLAGS_task_mmu.o\t+= -Wno-override-init\nfs/proc/Makefile-9-proc-y\t\t\t:= nommu.o task_nommu.o\nfs/proc/Makefile:10:proc-$(CONFIG_MMU)\t:= task_mmu.o\nfs/proc/Makefile-11-\n"
}

7/2 2026/07/01 00:11 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13860
							output: 23
							thoughts: 41
						

Thoughts:
Here's my summary, as the thought process unfolds:

**Dependencies and Scope**

Okay, so I see a flag—`CONFIG_MMU`—and it's pinging my brain. Ah, right, that's a prerequisite for `task_mmu.c`. I need to figure out how this ties into the bigger picture. My expertise says I should confirm that this is true. Where does this get used? I should investigate `mm_prepare_for_swap_entries`. Let's see... I'll check that function declaration within `mm/internal.h`. I need to understand its role and why it necessitates the MMU configuration.



8/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "mm_prepare_for_swap_entries"
}

Results:
{
  "Output": "mm/internal.h=1956=bool may_expand_vm(struct mm_struct *mm, const vma_flags_t *vma_flags,\n--\nmm/internal.h-1961- */\nmm/internal.h:1962:static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)\nmm/internal.h-1963-{\n--\nmm/memory.c=941=copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,\n--\nmm/memory.c-955-\nmm/memory.c:956:\t\tmm_prepare_for_swap_entries(dst_mm);\nmm/memory.c-957-\t\t/* Mark the swap entry as shared. */\n--\nmm/rmap.c=1984=static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n--\nmm/rmap.c-2306-\t\t\t}\nmm/rmap.c:2307:\t\t\tmm_prepare_for_swap_entries(mm);\nmm/rmap.c-2308-\t\t\tdec_mm_counter(mm, MM_ANONPAGES);\n"
}

9/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14382
							output: 25
							thoughts: 150
						

Thoughts:
**My Assessment of the Patch's Coverage**

Okay, the patch itself seems solid, it's definitely functional. Now, I need to make sure I've identified the right areas for its focus. I need to make sure I've got the most relevant symbols to analyze.

I'm thinking the key symbols to keep an eye on are: `pagemap_pmd_range_thp` – that's coming from `fs/proc/task_mmu.c`, which is logical given the context. Then there's `migrate_vma_collect_huge_pmd` from `mm/migrate_device.c`, important for memory migration, and `change_non_present_huge_pmd` from `mm/huge_memory.c`-- crucial for handling huge pages. Then `copy_nonpresent_pte` from `mm/memory.c` seems like a critical piece of the puzzle, dealing with page table entries. Finally, `try_to_unmap_one` from `mm/rmap.c` is going to be important in any unmapping scenario.

Alright, let's start with `pagemap_pmd_range_thp`. I'll verify if it's reachable and fully understood by the patch. That will be my starting point.



10/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "pagemap_pmd_range_thp"
}

Results:
{
  "Output": "fs/proc/task_mmu.c=2021=static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,\n--\nfs/proc/task_mmu.c-2087-#ifdef CONFIG_TRANSPARENT_HUGEPAGE\nfs/proc/task_mmu.c:2088:static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,\nfs/proc/task_mmu.c-2089-\t\tunsigned long end, struct vm_area_struct *vma,\n--\nfs/proc/task_mmu.c=2166=static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,\n--\nfs/proc/task_mmu.c-2177-\tif (ptl) {\nfs/proc/task_mmu.c:2178:\t\terr = pagemap_pmd_range_thp(pmdp, addr, end, vma, pm);\nfs/proc/task_mmu.c-2179-\t\tspin_unlock(ptl);\n"
}

11/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15136
							output: 25
							thoughts: 25
						

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

**Reaching the Target**

Alright, yep, looks like we're in a position to proceed. This is looking promising.

Let's quickly verify our assumptions by examining the `migrate_vma_collect_huge_pmd` function. We need to be absolutely certain this is the correct entry point to assess its role in this context before committing further resources. The architecture needs a sanity check.



12/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "migrate_vma_collect_huge_pmd"
}

Results:
{
  "Output": "arch/powerpc/include/asm/book3s/64/pgtable.h=1334=static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,\n--\narch/powerpc/include/asm/book3s/64/pgtable.h-1343-\t *   encounter non-present pmds.\narch/powerpc/include/asm/book3s/64/pgtable.h:1344:\t * - migrate_vma_collect_huge_pmd() could calls this during migration\narch/powerpc/include/asm/book3s/64/pgtable.h-1345-\t *   of device-private pmd entries.\n--\nmm/migrate_device.c=82=static int migrate_vma_split_folio(struct folio *folio,\n--\nmm/migrate_device.c-123-\nmm/migrate_device.c:124:/** migrate_vma_collect_huge_pmd - collect THP pages without splitting the\nmm/migrate_device.c-125- * folio for device private pages.\n--\nmm/migrate_device.c-135- */\nmm/migrate_device.c:136:static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,\nmm/migrate_device.c-137-\t\t\t\t\tunsigned long end, struct mm_walk *walk,\n--\nmm/migrate_device.c=244=static int migrate_vma_collect_pmd(pmd_t *pmdp,\n--\nmm/migrate_device.c-259-\tif (pmd_trans_huge(*pmdp) || !pmd_present(*pmdp)) {\nmm/migrate_device.c:260:\t\tint ret = migrate_vma_collect_huge_pmd(pmdp, start, end, walk, fault_folio);\nmm/migrate_device.c-261-\n"
}

13/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15790
							output: 24
							thoughts: 21
						

Thoughts:
Here's a summary of my immediate thought process, delivered as requested:

**Assessing Reachability and a Specific Function**

Okay, so I've confirmed something is achievable, reachable. My mind immediately jumps to a specific area of interest. I'm going to delve into the `change_non_present_huge_pmd` function. That seems like the logical next step.



14/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "change_non_present_huge_pmd"
}

Results:
{
  "Output": "mm/huge_memory.c=2504=bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,\n--\nmm/huge_memory.c-2554-\nmm/huge_memory.c:2555:static void change_non_present_huge_pmd(struct mm_struct *mm,\nmm/huge_memory.c-2556-\t\tunsigned long addr, pmd_t *pmd, bool uffd_wp,\n--\nmm/huge_memory.c=2601=int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,\n--\nmm/huge_memory.c-2622-\tif (thp_migration_supported() \u0026\u0026 pmd_is_valid_softleaf(*pmd)) {\nmm/huge_memory.c:2623:\t\tchange_non_present_huge_pmd(mm, addr, pmd, uffd_wp,\nmm/huge_memory.c-2624-\t\t\t\t\t    uffd_wp_resolve);\n"
}

15/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16195
							output: 20
							thoughts: 17
						

Thoughts:
Here's my take on those thoughts:

**Reaching for `copy_nonpresent_pte`**

Okay, yes, that sounds like a viable path forward. It seems like the goal is achievable. Now, where do I start? Let's zoom in and examine the implementation of `copy_nonpresent_pte`. It's likely that function holds the key to the solution. I need to understand its mechanics. Let's see what's in there.



16/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "copy_nonpresent_pte"
}

Results:
{
  "Output": "mm/memory.c=940=static unsigned long\nmm/memory.c:941:copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,\nmm/memory.c-942-\t\tpte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *dst_vma,\n--\nmm/memory.c=1217=copy_pte_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,\n--\nmm/memory.c-1288-\t\tif (unlikely(!pte_present(ptent))) {\nmm/memory.c:1289:\t\t\tret = copy_nonpresent_pte(dst_mm, src_mm,\nmm/memory.c-1290-\t\t\t\t\t\t  dst_pte, src_pte,\n--\nmm/mprotect.c=214=static long change_softleaf_pte(struct vm_area_struct *vma,\n--\nmm/mprotect.c-238-\t\t * We do not preserve soft-dirtiness. See\nmm/mprotect.c:239:\t\t * copy_nonpresent_pte() for explanation.\nmm/mprotect.c-240-\t\t */\n"
}

17/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16656
							output: 22
							thoughts: 19
						

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

**Reaching an Endpoint**

Yes, the objective is within grasp. I've confirmed that the path is valid and that the target can be reached.

My next step is to examine `try_to_unmap_one`. This function is pivotal in handling potential memory allocation conflicts, so understanding its behavior is crucial. I want to delve into the specifics of how it operates in the current context. It's time to analyze its role in either successfully or unsuccessfully completing the operation.



18/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "try_to_unmap_one"
}

Results:
{
  "Output": "Documentation/mm/process_addrs.rst=440=There is also a file-system specific lock ordering comment located at the top of\n--\nDocumentation/mm/process_addrs.rst-476-  -\u003epage_table_lock or pte_lock\nDocumentation/mm/process_addrs.rst:477:    -\u003eswap_lock                         (try_to_unmap_one)\nDocumentation/mm/process_addrs.rst:478:    -\u003eprivate_lock                      (try_to_unmap_one)\nDocumentation/mm/process_addrs.rst:479:    -\u003ei_pages lock                      (try_to_unmap_one)\nDocumentation/mm/process_addrs.rst-480-    -\u003elruvec-\u003elru_lock                  (follow_page_mask-\u003emark_page_accessed)\n--\nDocumentation/mm/unevictable-lru.rst=555=rmap's folio_referenced_one(), called via vmscan's shrink_active_list() or\nDocumentation/mm/unevictable-lru.rst:556:shrink_folio_list(), and rmap's try_to_unmap_one() called via shrink_folio_list(),\nDocumentation/mm/unevictable-lru.rst-557-check for (3) pages still mapped into VM_LOCKED VMAs, and call mlock_vma_folio()\n--\narch/arm64/include/asm/mmu.h=19=typedef struct {\n--\narch/arm64/include/asm/mmu.h-33- * rollover event (see new_context() and flush_context()). In this case,\narch/arm64/include/asm/mmu.h:34: * a concurrent TLBI (e.g. via try_to_unmap_one() and ptep_clear_flush())\narch/arm64/include/asm/mmu.h-35- * may use a stale ASID. This is fine in principle as the new ASID is\n--\nfs/nilfs2/inode.c=177=static bool nilfs_dirty_folio(struct address_space *mapping,\n--\nfs/nilfs2/inode.c-185-\t/*\nfs/nilfs2/inode.c:186:\t * The page may not be locked, eg if called from try_to_unmap_one()\nfs/nilfs2/inode.c-187-\t */\n--\nmm/filemap.c-114- *  -\u003epage_table_lock or pte_lock\nmm/filemap.c:115: *    -\u003eswap_lock\t\t(try_to_unmap_one)\nmm/filemap.c:116: *    -\u003eprivate_lock\t\t(try_to_unmap_one)\nmm/filemap.c:117: *    -\u003ei_pages lock\t\t(try_to_unmap_one)\nmm/filemap.c-118- *    -\u003elruvec-\u003elru_lock\t(follow_page_mask-\u003emark_page_accessed)\n--\nmm/memory-failure.c=2385=int memory_failure(unsigned long pfn, int flags)\n--\nmm/memory-failure.c-2570-\t * example is an mlocked page, where PG_mlocked is cleared by\nmm/memory-failure.c:2571:\t * folio_remove_rmap_*() in try_to_unmap_one(). So to determine page\nmm/memory-failure.c-2572-\t * status correctly, we save a copy of the page flags at this time.\n--\nmm/mlock.c=467=static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma,\n--\nmm/mlock.c-503-\t * vm_flags is protected by the mmap_lock held in write mode.\nmm/mlock.c:504:\t * It's okay if try_to_unmap_one unmaps a page just after we\nmm/mlock.c-505-\t * set VM_LOCKED, populate_vma_page_range will bring it back.\n--\nmm/rmap.c=1944=static inline unsigned int folio_unmap_pte_batch(struct folio *folio,\n--\nmm/rmap.c-1983- */\nmm/rmap.c:1984:static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\nmm/rmap.c-1985-\t\t     unsigned long address, void *arg)\n--\nmm/rmap.c=2389=void try_to_unmap(struct folio *folio, enum ttu_flags flags)\n--\nmm/rmap.c-2391-\tstruct rmap_walk_control rwc = {\nmm/rmap.c:2392:\t\t.rmap_one = try_to_unmap_one,\nmm/rmap.c-2393-\t\t.arg = (void *)flags,\n"
}

19/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 18057
							output: 20
							thoughts: 97
						

Thoughts:
**Configuration Verification for Transparent Hugepages and Device Migration**

Okay, so the goal is definitely achievable. Now, let's make sure everything is configured correctly. First things first, I need to confirm that `CONFIG_TRANSPARENT_HUGEPAGE` is enabled – that's crucial. I also know `CONFIG_DEVICE_MIGRATION` is essential for the functionality I'm after, and I'll need to double-check that. Of course, `CONFIG_MMU` is generally enabled by default, but I'll make a mental note to confirm it's present. And, given that migration is central to the process, I see I'll need `CONFIG_MIGRATION` for `mm/migrate.c`. I should probably cross-reference `CONFIG_DEVICE_MIGRATION` in `mm/Kconfig` just to make sure I understand its dependencies and relationships within the memory management subsystem before I move forward.



20/2 2026/07/01 00:12 tool grepper
0m Args:
{
  "Expression": "config DEVICE_MIGRATION"
}

Results:
{
  "Output": "mm/Kconfig=696=config MIGRATION\n--\nmm/Kconfig-699-\nmm/Kconfig:700:config DEVICE_MIGRATION\nmm/Kconfig-701-\tdef_bool MIGRATION \u0026\u0026 ZONE_DEVICE\n"
}

21/2 2026/07/01 00:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 18449
							output: 22
							thoughts: 43
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Configuration Considerations for Memory Management**

Alright, so we're dealing with zone devices and migration – those are definitely key, so `CONFIG_ZONE_DEVICE` and `CONFIG_MIGRATION` are essential prerequisites. Now, I need to confirm whether transparent hugepages will be impacting this setup. Given the context, it's reasonable to check the `mm/Kconfig` file, as the Transparent Hugepage settings are located there. That's the logical next step.



22/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "config TRANSPARENT_HUGEPAGE"
}

Results:
{
  "Output": "mm/Kconfig=843=config MM_ID\n--\nmm/Kconfig-845-\nmm/Kconfig:846:menuconfig TRANSPARENT_HUGEPAGE\nmm/Kconfig-847-\tbool \"Transparent Hugepage Support\"\n--\nmm/Kconfig=864=choice\n--\nmm/Kconfig-869-\nmm/Kconfig:870:\tconfig TRANSPARENT_HUGEPAGE_ALWAYS\nmm/Kconfig-871-\t\tbool \"always\"\n--\nmm/Kconfig-876-\nmm/Kconfig:877:\tconfig TRANSPARENT_HUGEPAGE_MADVISE\nmm/Kconfig-878-\t\tbool \"madvise\"\n--\nmm/Kconfig-885-\nmm/Kconfig:886:\tconfig TRANSPARENT_HUGEPAGE_NEVER\nmm/Kconfig-887-\t\tbool \"never\"\n--\nmm/Kconfig=893=choice\n--\nmm/Kconfig-902-\nmm/Kconfig:903:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_NEVER\nmm/Kconfig-904-\t\tbool \"never\"\n--\nmm/Kconfig-912-\nmm/Kconfig:913:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ALWAYS\nmm/Kconfig-914-\t\tbool \"always\"\n--\nmm/Kconfig-920-\nmm/Kconfig:921:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_WITHIN_SIZE\nmm/Kconfig-922-\t\tbool \"within_size\"\n--\nmm/Kconfig-928-\nmm/Kconfig:929:\tconfig TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ADVISE\nmm/Kconfig-930-\t\tbool \"advise\"\n--\nmm/Kconfig=938=choice\n--\nmm/Kconfig-947-\nmm/Kconfig:948:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_NEVER\nmm/Kconfig-949-\t\tbool \"never\"\n--\nmm/Kconfig-956-\nmm/Kconfig:957:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ALWAYS\nmm/Kconfig-958-\t\tbool \"always\"\n--\nmm/Kconfig-964-\nmm/Kconfig:965:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_WITHIN_SIZE\nmm/Kconfig-966-\t\tbool \"within_size\"\n--\nmm/Kconfig-972-\nmm/Kconfig:973:\tconfig TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ADVISE\nmm/Kconfig-974-\t\tbool \"advise\"\n"
}

23/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 19348
							output: 17
							thoughts: 36
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating Transparent Hugepages and HMM Mirroring**

Right, *Transparent Hugepages* are the immediate requirement here. Need to make sure those are properly configured and operational.

Now, where did I see something related to handling memory mirroring? That rings a bell... I think it might be in `hmm.c`. Let me just quickly scan the kernel configuration options... Yes, I need to check for `CONFIG_HMM_MIRROR` or something *similar* within the `hmm.c` code. Specifically, the interplay of THP with any memory mirroring implementations is what I'm interested in to confirm correct behavior.



24/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "hmm.o"
}

Results:
{
  "Output": "drivers/accel/amdxdna/amdxdna_gem.c=247=static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni,\n--\ndrivers/accel/amdxdna/amdxdna_gem.c-282-\ndrivers/accel/amdxdna/amdxdna_gem.c:283:static const struct mmu_interval_notifier_ops amdxdna_hmm_ops = {\ndrivers/accel/amdxdna/amdxdna_gem.c-284-\t.invalidate = amdxdna_hmm_invalidate,\n--\ndrivers/accel/amdxdna/amdxdna_gem.c=342=static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo,\n--\ndrivers/accel/amdxdna/amdxdna_gem.c-372-\t\t\t\t\t\t  len,\ndrivers/accel/amdxdna/amdxdna_gem.c:373:\t\t\t\t\t\t  \u0026amdxdna_hmm_ops);\ndrivers/accel/amdxdna/amdxdna_gem.c-374-\tif (ret) {\n--\ndrivers/gpu/drm/amd/amdgpu/Makefile=322=amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o\ndrivers/gpu/drm/amd/amdgpu/Makefile:323:amdgpu-$(CONFIG_HMM_MIRROR) += amdgpu_hmm.o\ndrivers/gpu/drm/amd/amdgpu/Makefile-324-\n--\ndrivers/infiniband/core/umem_odp.c=324=int ib_umem_odp_map_dma_and_lock(struct ib_umem_odp *umem_odp, u64 user_virt,\n--\ndrivers/infiniband/core/umem_odp.c-330-\tint pfn_index, dma_index, ret = 0, start_idx;\ndrivers/infiniband/core/umem_odp.c:331:\tunsigned int page_shift, hmm_order, pfn_start_idx;\ndrivers/infiniband/core/umem_odp.c-332-\tunsigned long num_pfns, current_seq;\n--\ndrivers/infiniband/core/umem_odp.c-404-\ndrivers/infiniband/core/umem_odp.c:405:\t\thmm_order = hmm_pfn_to_map_order(range.hmm_pfns[pfn_index]);\ndrivers/infiniband/core/umem_odp.c-406-\t\t/* If a hugepage was detected and ODP wasn't set for, the umem\n--\ndrivers/infiniband/core/umem_odp.c-408-\t\t */\ndrivers/infiniband/core/umem_odp.c:409:\t\tif (hmm_order + PAGE_SHIFT \u003c page_shift) {\ndrivers/infiniband/core/umem_odp.c-410-\t\t\tret = -EINVAL;\ndrivers/infiniband/core/umem_odp.c-411-\t\t\tibdev_dbg(umem_odp-\u003eumem.ibdev,\ndrivers/infiniband/core/umem_odp.c:412:\t\t\t\t  \"%s: un-expected hmm_order %u, page_shift %u\\n\",\ndrivers/infiniband/core/umem_odp.c:413:\t\t\t\t  __func__, hmm_order, page_shift);\ndrivers/infiniband/core/umem_odp.c-414-\t\t\tbreak;\n--\ndrivers/staging/media/atomisp/Makefile=15=atomisp-objs += \\\n--\ndrivers/staging/media/atomisp/Makefile-44-\tpci/hmm/hmm_bo.o \\\ndrivers/staging/media/atomisp/Makefile:45:\tpci/hmm/hmm.o \\\ndrivers/staging/media/atomisp/Makefile-46-\tpci/ia_css_device_access.o \\\n--\nlib/Makefile=102=obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o\nlib/Makefile:103:obj-$(CONFIG_TEST_HMM) += test_hmm.o\nlib/Makefile-104-obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o\n--\nmm/Makefile=138=obj-$(CONFIG_ZONE_DEVICE) += memremap.o\nmm/Makefile:139:obj-$(CONFIG_HMM_MIRROR) += hmm.o\nmm/Makefile-140-obj-$(CONFIG_MEMFD_CREATE) += memfd.o\n--\ntools/testing/selftests/mm/hmm-tests.c=119=FIXTURE_VARIANT_ADD(hmm2, hmm2_device_coherent)\n--\ntools/testing/selftests/mm/hmm-tests.c-124-\ntools/testing/selftests/mm/hmm-tests.c:125:static int hmm_open(int unit)\ntools/testing/selftests/mm/hmm-tests.c-126-{\n--\ntools/testing/selftests/mm/hmm-tests.c=143=FIXTURE_SETUP(hmm)\n--\ntools/testing/selftests/mm/hmm-tests.c-147-\ntools/testing/selftests/mm/hmm-tests.c:148:\tself-\u003efd = hmm_open(variant-\u003edevice_number);\ntools/testing/selftests/mm/hmm-tests.c-149-\tif (self-\u003efd \u003c 0 \u0026\u0026 hmm_is_coherent_type(variant-\u003edevice_number))\n--\ntools/testing/selftests/mm/hmm-tests.c=154=FIXTURE_SETUP(hmm2)\n--\ntools/testing/selftests/mm/hmm-tests.c-158-\ntools/testing/selftests/mm/hmm-tests.c:159:\tself-\u003efd0 = hmm_open(variant-\u003edevice_number0);\ntools/testing/selftests/mm/hmm-tests.c-160-\tif (self-\u003efd0 \u003c 0 \u0026\u0026 hmm_is_coherent_type(variant-\u003edevice_number0))\n--\ntools/testing/selftests/mm/hmm-tests.c-162-\tASSERT_GE(self-\u003efd0, 0);\ntools/testing/selftests/mm/hmm-tests.c:163:\tself-\u003efd1 = hmm_open(variant-\u003edevice_number1);\ntools/testing/selftests/mm/hmm-tests.c-164-\tASSERT_GE(self-\u003efd1, 0);\n--\ntools/testing/selftests/mm/hmm-tests.c=542=TEST_F(hmm, anon_write_child)\n--\ntools/testing/selftests/mm/hmm-tests.c-623-\t\t\t/* The child process needs its own mirror to its own mm. */\ntools/testing/selftests/mm/hmm-tests.c:624:\t\t\tchild_fd = hmm_open(0);\ntools/testing/selftests/mm/hmm-tests.c-625-\t\t\tASSERT_GE(child_fd, 0);\n--\ntools/testing/selftests/mm/hmm-tests.c=649=TEST_F(hmm, anon_write_child_shared)\n--\ntools/testing/selftests/mm/hmm-tests.c-705-\t/* The child process needs its own mirror to its own mm. */\ntools/testing/selftests/mm/hmm-tests.c:706:\tchild_fd = hmm_open(0);\ntools/testing/selftests/mm/hmm-tests.c-707-\tASSERT_GE(child_fd, 0);\n"
}

25/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 21514
							output: 18
							thoughts: 257
						

Thoughts:
**My Configuration Puzzle**

Okay, so I'm putting together the kernel configuration, and it looks like `CONFIG_HMM_MIRROR` is definitely a prerequisite for `hmm.c`. Got it. Let me just confirm that in my notes.

Now, let's double-check the dependencies for `CONFIG_DEVICE_MIGRATION` within `mm/Kconfig`. Right, it depends on `MIGRATION` and `ZONE_DEVICE`. So, `CONFIG_ZONE_DEVICE` is essential here. I knew there was something else in that mix.

Now let's check `CONFIG_MIGRATION`. Ah, it's enabled by default if either `NUMA` or `COMPACTION` is enabled. That should be straight forward.

Let's check `CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF`. Actually, no, it looks like it's indirectly enabled. It's selected by `TRANSPARENT_HUGEPAGE`, so no need to manage that directly. Saved that for later.

Alright, so the key configurations I need to enable are: `TRANSPARENT_HUGEPAGE`, `DEVICE_MIGRATION`, `ZONE_DEVICE`, and `HMM_MIRROR`.

Wait, hold on, `DEVICE_MIGRATION` is a `def_bool MIGRATION && ZONE_DEVICE`. So I can't enable it directly. I need to make sure `ZONE_DEVICE` and `MIGRATION` are enabled. I'll need to go back and check if enabling `MIGRATION` has any further dependencies. I better go and check `ZONE_DEVICE` in `mm/Kconfig` too, just to be sure. That configuration will be important.



26/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "config ZONE_DEVICE"
}

Results:
{
  "Output": "mm/Kconfig=1231=config ZONE_DMA32\n--\nmm/Kconfig-1235-\nmm/Kconfig:1236:config ZONE_DEVICE\nmm/Kconfig-1237-\tbool \"Device memory (pmem, HMM, etc...) hotplug support\"\n"
}

27/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 22247
							output: 20
							thoughts: 29
						

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

**Investigating a Configuration Variable**

Alright, so I'm looking at `ZONE_DEVICE`, which the code seems to treat as a straightforward boolean. Okay, that's fine, but I'd like to understand the context and the potential dependencies a bit better. This usually leads me to dig deeper into the configuration options.

Given its purpose, my next logical step is to check how `HMM_MIRROR` is defined and used. I'll need to head over to the `mm/Kconfig` file. That's where all the memory management related configurations live, so that's the place to refresh my memory, confirm my assumptions and ensure I have the full picture. I need to be sure that the interaction between `ZONE_DEVICE` and `HMM_MIRROR` is well-understood. Let's see what the Kconfig says.



28/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "config HMM_MIRROR"
}

Results:
{
  "Output": "mm/Kconfig=1236=config ZONE_DEVICE\n--\nmm/Kconfig-1259-#\nmm/Kconfig:1260:config HMM_MIRROR\nmm/Kconfig-1261-\tbool\n"
}

29/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 22566
							output: 20
							thoughts: 41
						

Thoughts:
**Analyzing the `HMM_MIRROR` Configuration**

Okay, so `HMM_MIRROR` is a boolean, a straightforward on/off kind of setting. The thing that immediately grabs my attention is that there's no associated prompt defined for it. That's a bit unusual, and it tells me this isn't something the user is likely directly configuring through a standard menu. It's probably selected internally, likely by the drivers themselves, based on some underlying condition or detection. This means I need to figure out *what* exactly is triggering that selection. My next step is clear: I need to trace back and determine the conditions or code paths that are setting this particular boolean. That's where the real insights will be.



30/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "select HMM_MIRROR"
}

Results:
{
  "Output": "drivers/accel/amdxdna/Kconfig=3=config DRM_ACCEL_AMDXDNA\n--\ndrivers/accel/amdxdna/Kconfig-11-\tselect FW_LOADER\ndrivers/accel/amdxdna/Kconfig:12:\tselect HMM_MIRROR\ndrivers/accel/amdxdna/Kconfig-13-\thelp\n--\ndrivers/gpu/drm/Kconfig=228=config DRM_GPUSVM\n--\ndrivers/gpu/drm/Kconfig-230-\tdepends on DRM\ndrivers/gpu/drm/Kconfig:231:\tselect HMM_MIRROR\ndrivers/gpu/drm/Kconfig-232-\tselect MMU_NOTIFIER\n--\ndrivers/gpu/drm/amd/amdgpu/Kconfig=75=config DRM_AMDGPU_USERPTR\n--\ndrivers/gpu/drm/amd/amdgpu/Kconfig-77-\tdepends on DRM_AMDGPU\ndrivers/gpu/drm/amd/amdgpu/Kconfig:78:\tselect HMM_MIRROR\ndrivers/gpu/drm/amd/amdgpu/Kconfig-79-\tselect MMU_NOTIFIER\n--\ndrivers/gpu/drm/amd/amdkfd/Kconfig=6=config HSA_AMD\n--\ndrivers/gpu/drm/amd/amdkfd/Kconfig-8-\tdepends on DRM_AMDGPU \u0026\u0026 (X86_64 || ARM64 || PPC64 || (RISCV \u0026\u0026 64BIT) || (LOONGARCH \u0026\u0026 64BIT))\ndrivers/gpu/drm/amd/amdkfd/Kconfig:9:\tselect HMM_MIRROR\ndrivers/gpu/drm/amd/amdkfd/Kconfig-10-\tselect MMU_NOTIFIER\n--\ndrivers/gpu/drm/amd/amdkfd/Kconfig=15=config HSA_AMD_SVM\n--\ndrivers/gpu/drm/amd/amdkfd/Kconfig-18-\tdefault y\ndrivers/gpu/drm/amd/amdkfd/Kconfig:19:\tselect HMM_MIRROR\ndrivers/gpu/drm/amd/amdkfd/Kconfig-20-\tselect MMU_NOTIFIER\n--\ndrivers/gpu/drm/nouveau/Kconfig=94=config DRM_NOUVEAU_SVM\n--\ndrivers/gpu/drm/nouveau/Kconfig-98-\tdepends on STAGING\ndrivers/gpu/drm/nouveau/Kconfig:99:\tselect HMM_MIRROR\ndrivers/gpu/drm/nouveau/Kconfig-100-\tselect MMU_NOTIFIER\n--\ndrivers/hv/Kconfig=68=config MSHV_ROOT\n--\ndrivers/hv/Kconfig-79-\tselect VIRT_XFER_TO_GUEST_WORK\ndrivers/hv/Kconfig:80:\tselect HMM_MIRROR\ndrivers/hv/Kconfig-81-\tselect MMU_NOTIFIER\n--\ndrivers/infiniband/Kconfig=51=config INFINIBAND_ON_DEMAND_PAGING\n--\ndrivers/infiniband/Kconfig-55-\tselect INTERVAL_TREE\ndrivers/infiniband/Kconfig:56:\tselect HMM_MIRROR\ndrivers/infiniband/Kconfig-57-\tdefault y\n--\nlib/Kconfig.debug=3326=config TEST_HMM\n--\nlib/Kconfig.debug-3329-\tdepends on DEVICE_PRIVATE\nlib/Kconfig.debug:3330:\tselect HMM_MIRROR\nlib/Kconfig.debug-3331-\tselect MMU_NOTIFIER\n--\nmm/Kconfig=1267=config DEVICE_PRIVATE\n--\nmm/Kconfig-1274-\t  memory; i.e., memory that is only accessible from the device (or\nmm/Kconfig:1275:\t  group of devices). You likely also want to select HMM_MIRROR.\nmm/Kconfig-1276-\n"
}

31/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 23756
							output: 18
							thoughts: 48
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience:

**Analyzing HMM Configuration Dependencies**

Alright, let's break this down. It looks like the system is set up so that the `TEST_HMM` configuration option, which I assume is for some kind of Hidden Markov Model testing, is triggering the selection of `HMM_MIRROR`. That's a reasonable connection; mirroring might be a prerequisite or a supporting element for proper HMM testing. So, enabling `TEST_HMM` directly implies the activation of the mirror configuration. Now, I see that `TEST_HMM` also has a dependency on `DEVICE_PRIVATE`. Naturally, before I proceed with any testing, or making a decision on how to proceed, I need to understand that. I'll need to check the definition of `DEVICE_PRIVATE`. Knowing exactly what that component encompasses is crucial to understand if enabling it for testing has any impact, perhaps on security, resource allocation, or any other area of the system. Let's see what that flag is all about.



32/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "config DEVICE_PRIVATE"
}

Results:
{
  "Output": "mm/Kconfig=1264=config GET_FREE_REGION\n--\nmm/Kconfig-1266-\nmm/Kconfig:1267:config DEVICE_PRIVATE\nmm/Kconfig-1268-\tbool \"Unaddressable device memory (GPU memory, ...)\"\n"
}

33/2 2026/07/01 00:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 24130
							output: 18
							thoughts: 41
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own mental processing:

**Dependency Deep Dive for Device Features**

Alright, it looks like the plan is to enable `DEVICE_PRIVATE` and `TEST_HMM`. Makes sense, those are key for the upcoming analysis. However, I recall that `DEVICE_PRIVATE` isn't a standalone feature. My internal dependency graph is already highlighting that `DEVICE_PRIVATE` is contingent on `ZONE_DEVICE`. So, before I commit to enabling `DEVICE_PRIVATE`, I need to make sure `ZONE_DEVICE` is sorted. Let's make sure that's set properly before going any further down this path. I need to quickly run through the relevant configurations and make a few minor adjustments to ensure the prerequisites are met. I am not seeing that as an issue, just a checkpoint.



34/2 2026/07/01 00:13 tool grepper
0m Args:
{
  "Expression": "config DEVICE_PRIVATE"
}

Results:
{
  "Output": "mm/Kconfig=1264=config GET_FREE_REGION\n--\nmm/Kconfig-1266-\nmm/Kconfig:1267:config DEVICE_PRIVATE\nmm/Kconfig-1268-\tbool \"Unaddressable device memory (GPU memory, ...)\"\n"
}

35/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 24449
							output: 33
							thoughts: 19
						

Thoughts:
Here's my thought process, as if I were considering this myself:

**Investigating `mm/Kconfig` and `DEVICE_PRIVATE`**

Okay, hold on a second. Before I dive too deep, let's just quickly check `mm/Kconfig`. I've got this gut feeling that `DEVICE_PRIVATE` is going to be relevant here. It's a common area for memory management configuration options, and the name definitely rings a bell. My experience suggests that this particular section often houses settings related to device-specific memory allocations or permissions, so that's the natural place to start looking. I need to refresh my memory on the interactions of memory management configuration. This should provide some solid context.



36/2 2026/07/01 00:14 tool read-file
0m Args:
{
  "File": "mm/Kconfig",
  "FirstLine": 1260,
  "LineCount": 20
}

Results:
{
  "Contents": "1260:\tconfig HMM_MIRROR\n1261:\t\tbool\n1262:\t\tdepends on MMU\n1263:\t\n1264:\tconfig GET_FREE_REGION\n1265:\t\tbool\n1266:\t\n1267:\tconfig DEVICE_PRIVATE\n1268:\t\tbool \"Unaddressable device memory (GPU memory, ...)\"\n1269:\t\tdepends on ZONE_DEVICE\n1270:\t\tselect GET_FREE_REGION\n1271:\t\n1272:\t\thelp\n1273:\t\t  Allows creation of struct pages to represent unaddressable device\n1274:\t\t  memory; i.e., memory that is only accessible from the device (or\n1275:\t\t  group of devices). You likely also want to select HMM_MIRROR.\n1276:\t\n1277:\tconfig VMAP_PFN\n1278:\t\tbool\n1279:\t\n"
}

37/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 24905
							output: 33
							thoughts: 25
						

Thoughts:
Okay, here's my take on those thoughts, framed for an expert like yourself:

**Dependency Deep Dive**

Right, so I'm looking at `DEVICE_PRIVATE` here, and it's pretty clear that it has a dependency on `ZONE_DEVICE`. Nothing unexpected there, but now I need to understand that `ZONE_DEVICE` itself is hooked up to. Let's dig into the dependencies of `ZONE_DEVICE` to see what else this affects. It's time to build out that dependency graph and make sure we understand all the consequences of these relationships. I need to make sure I don't miss anything that gets cascaded by that connection.



38/2 2026/07/01 00:14 tool read-file
0m Args:
{
  "File": "mm/Kconfig",
  "FirstLine": 1230,
  "LineCount": 20
}

Results:
{
  "Contents": "1230:\t\n1231:\tconfig ZONE_DMA32\n1232:\t\tbool \"Support DMA32 zone\" if ARCH_HAS_ZONE_DMA_SET\n1233:\t\tdepends on !X86_32\n1234:\t\tdefault y if ARM64\n1235:\t\n1236:\tconfig ZONE_DEVICE\n1237:\t\tbool \"Device memory (pmem, HMM, etc...) hotplug support\"\n1238:\t\tdepends on MEMORY_HOTPLUG\n1239:\t\tdepends on MEMORY_HOTREMOVE\n1240:\t\tdepends on SPARSEMEM_VMEMMAP\n1241:\t\tselect XARRAY_MULTI\n1242:\t\n1243:\t\thelp\n1244:\t\t  Device memory hotplug support allows for establishing pmem,\n1245:\t\t  or other device driver discovered memory regions, in the\n1246:\t\t  memmap. This allows pfn_to_page() lookups of otherwise\n1247:\t\t  \"device-physical\" addresses which is needed for DAX, PCI_P2PDMA, and\n1248:\t\t  DEVICE_PRIVATE features among others.\n1249:\t\n"
}

39/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 25417
							output: 32
							thoughts: 54
						

Thoughts:
Okay, here's my interpretation of these thoughts, formatted as you requested:

**Dependency Deep Dive: ZONE_DEVICE**

Right, so `ZONE_DEVICE`. That's an interesting one, and I'm immediately thinking about its relationships. I know that `ZONE_DEVICE` relies pretty heavily on a few other key features. Specifically, I'm thinking of `MEMORY_HOTPLUG`, `MEMORY_HOTREMOVE`, and `SPARSEMEM_VMEMMAP`. Those seem like fundamental building blocks for anything dealing with device memory zones. I've often seen these enabled, especially when I'm working with syzkaller configurations, which tends to be where I'm poking around in this kind of area. It makes sense, given syzkaller's focus on fault injection and testing.

Now, I should probably also quickly check `DEVICE_MIGRATION`, given the context.



40/2 2026/07/01 00:14 tool read-file
0m Args:
{
  "File": "mm/Kconfig",
  "FirstLine": 690,
  "LineCount": 20
}

Results:
{
  "Contents": " 690:\t\thelp\n 691:\t\t  Support the migration of pages to other NUMA nodes, available to\n 692:\t\t  user space through interfaces like migrate_pages(), move_pages(),\n 693:\t\t  and mbind(). Selecting this option also enables support for page\n 694:\t\t  demotion for memory tiering.\n 695:\t\n 696:\tconfig MIGRATION\n 697:\t\tbool\n 698:\t\tdepends on MMU\n 699:\t\n 700:\tconfig DEVICE_MIGRATION\n 701:\t\tdef_bool MIGRATION \u0026\u0026 ZONE_DEVICE\n 702:\t\n 703:\tconfig ARCH_ENABLE_HUGEPAGE_MIGRATION\n 704:\t\tbool\n 705:\t\n 706:\tconfig ARCH_SUPPORTS_PMD_SOFTLEAF\n 707:\t\tbool\n 708:\t\n 709:\tconfig HUGETLB_PAGE_SIZE_VARIABLE\n"
}

41/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 25956
							output: 35
							thoughts: 39
						

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

**Automatic Device Migration and Dependency Checks**

Right, so it's clear that the system automatically enables `DEVICE_MIGRATION` when both `MIGRATION` and `ZONE_DEVICE` features are active. That makes perfect sense; it streamlines the setup and reduces potential for manual configuration errors, which is always a good thing. We need to be wary of automatic functionality, and consider the edge cases, but the design seems sound at first glance. Now, let's switch gears and check the dependencies of `TEST_HMM`. I need to ensure nothing's been missed during integration; this could be vital, and unexpected behaviors are the bane of my existence. What could it depend on in the current configuration? Let's trace this and make certain we are not overlooking something here.



42/2 2026/07/01 00:14 tool read-file
0m Args:
{
  "File": "lib/Kconfig.debug",
  "FirstLine": 3320,
  "LineCount": 20
}

Results:
{
  "Contents": "3320:\t\thelp\n3321:\t\t  Test if the kernel is zero-initializing heap and page allocations.\n3322:\t\t  This can be useful to test init_on_alloc and init_on_free features.\n3323:\t\n3324:\t\t  If unsure, say N.\n3325:\t\n3326:\tconfig TEST_HMM\n3327:\t\ttristate \"Test HMM (Heterogeneous Memory Management)\"\n3328:\t\tdepends on TRANSPARENT_HUGEPAGE\n3329:\t\tdepends on DEVICE_PRIVATE\n3330:\t\tselect HMM_MIRROR\n3331:\t\tselect MMU_NOTIFIER\n3332:\t\thelp\n3333:\t\t  This is a pseudo device driver solely for testing HMM.\n3334:\t\t  Say M here if you want to build the HMM test module.\n3335:\t\t  Doing so will allow you to run tools/testing/selftest/vm/hmm-tests.\n3336:\t\n3337:\t\t  If unsure, say N.\n3338:\t\n3339:\tconfig TEST_FREE_PAGES\n"
}

43/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 26521
							output: 22
							thoughts: 558
						

Thoughts:
**Analyzing Kernel Configuration Dependencies for HMM Testing**

Okay, so I'm diving into this `TEST_HMM` configuration option. Right off the bat, I see it's dependent on `TRANSPARENT_HUGEPAGE` and `DEVICE_PRIVATE`. So, that means I need to make sure those are enabled, along with `ZONE_DEVICE` since it looks like it's a piece of the puzzle. The obvious ones to enable are `TRANSPARENT_HUGEPAGE`, `ZONE_DEVICE`, `DEVICE_PRIVATE`, and of course `TEST_HMM` itself.

Hmm, `TRANSPARENT_HUGEPAGE`... it's a menuconfig, but it's also a bool. Let me clarify that; `TRANSPARENT_HUGEPAGE` is definitely a boolean. I don't think I need to worry about `TRANSPARENT_HUGEPAGE_ALWAYS` or any of those similar options; `TRANSPARENT_HUGEPAGE` is usually sufficient.

Next up, I need to check if `MIGRATION` is enabled. It's a boolean without a prompt, so it depends on `NUMA`, `COMPACTION`, or `MEMORY_HOTREMOVE`. Since `ZONE_DEVICE` depends on `MEMORY_HOTREMOVE`, that means `MIGRATION` is going to be enabled as well. Good, that simplifies things a bit.

So, just to reiterate, the key configs I need to have set are: `TRANSPARENT_HUGEPAGE`, `ZONE_DEVICE`, `DEVICE_PRIVATE`, and `TEST_HMM`.

Now, let's look at the code. I need to confirm the dependencies in the actual kernel code. I'll check `pagemap_pmd_range_thp` in `fs/proc/task_mmu.c`. Yep, it requires `CONFIG_TRANSPARENT_HUGEPAGE`, which I expect.

Okay, let's move on to `migrate_vma_collect_huge_pmd` in `mm/migrate_device.c`. That looks like it needs `CONFIG_DEVICE_MIGRATION`, which is defined as `MIGRATION && ZONE_DEVICE`. Check.

Next, I need to look at `change_non_present_huge_pmd` in `mm/huge_memory.c`. Yep, it requires `CONFIG_TRANSPARENT_HUGEPAGE` as well. Seems consistent.

Now, let's briefly check `copy_nonpresent_pte` in `mm/memory.c`. It depends on `CONFIG_MMU`. Makes sense; that's fundamental.

And finally, `try_to_unmap_one` in `mm/rmap.c` requires `CONFIG_MMU`, just as expected.

Okay, let me keep some of these functions in mind as I continue to explore this area: `pagemap_pmd_range_thp`, `migrate_vma_collect_huge_pmd`, `change_non_present_huge_pmd`, `copy_nonpresent_pte`, and `try_to_unmap_one`. I should also keep an eye on `set_pmd_migration_entry`, `remove_migration_pmd`, and `migrate_vma_insert_huge_pmd_page`. This should provide enough context to dive deeper.



44/2 2026/07/01 00:14 tool grepper
0m Args:
{
  "Expression": "set_pmd_migration_entry"
}

Results:
{
  "Output": "include/linux/swapops.h=322=struct page_vma_mapped_walk;\n--\ninclude/linux/swapops.h-324-#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\ninclude/linux/swapops.h:325:extern int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\ninclude/linux/swapops.h-326-\t\tstruct page *page);\n--\ninclude/linux/swapops.h=333=static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)\n--\ninclude/linux/swapops.h-341-#else  /* CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\ninclude/linux/swapops.h:342:static inline int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\ninclude/linux/swapops.h-343-\t\tstruct page *page)\n--\nmm/huge_memory.c=3031=static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,\n--\nmm/huge_memory.c-3192-\t\t * managed to clear PageAnonExclusive() -- see\nmm/huge_memory.c:3193:\t\t * set_pmd_migration_entry().\nmm/huge_memory.c-3194-\t\t *\n--\nmm/huge_memory.c=4864=late_initcall(split_huge_pages_debugfs);\n--\nmm/huge_memory.c-4867-#ifdef CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF\nmm/huge_memory.c:4868:int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\nmm/huge_memory.c-4869-\t\tstruct page *page)\n--\nmm/migrate_device.c=136=static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,\n--\nmm/migrate_device.c-213-\t\tmigrate-\u003ecpages++;\nmm/migrate_device.c:214:\t\tret = set_pmd_migration_entry(\u0026pvmw, folio_page(folio, 0));\nmm/migrate_device.c-215-\t\tif (ret) {\n--\nmm/rmap.c=2410=static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,\n--\nmm/rmap.c-2486-\nmm/rmap.c:2487:\t\t\tif (set_pmd_migration_entry(\u0026pvmw, subpage)) {\nmm/rmap.c-2488-\t\t\t\tret = false;\n"
}

45/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 28545
							output: 20
							thoughts: 28
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, and delivered as a first-person summary:

**Reaching a Crucial Point in PMD Migration**

Alright, so `set_pmd_migration_entry` is definitely reachable; that's good. Now that I've confirmed that, I need to shift focus. My next logical step in this workflow is to deeply analyze `remove_migration_pmd`. This function is pivotal, and I need to verify its interactions with the rest of the migration system. I need to understand its behavior thoroughly before I proceed with any further debugging or optimization, as removing the wrong entries will break everything.



46/2 2026/07/01 00:14 tool grepper
0m Args:
{
  "Expression": "remove_migration_pmd"
}

Results:
{
  "Output": "include/linux/swapops.h=325=extern int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n--\ninclude/linux/swapops.h-327-\ninclude/linux/swapops.h:328:extern void remove_migration_pmd(struct page_vma_mapped_walk *pvmw,\ninclude/linux/swapops.h-329-\t\tstruct page *new);\n--\ninclude/linux/swapops.h=342=static inline int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n--\ninclude/linux/swapops.h-347-\ninclude/linux/swapops.h:348:static inline void remove_migration_pmd(struct page_vma_mapped_walk *pvmw,\ninclude/linux/swapops.h-349-\t\tstruct page *new)\n--\ninclude/trace/events/thp.h=90=DEFINE_EVENT(migration_pmd, set_migration_pmd,\n--\ninclude/trace/events/thp.h-94-\ninclude/trace/events/thp.h:95:DEFINE_EVENT(migration_pmd, remove_migration_pmd,\ninclude/trace/events/thp.h-96-\tTP_PROTO(unsigned long addr, unsigned long pmd),\n--\nmm/huge_memory.c=4868=int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,\n--\nmm/huge_memory.c-4941-\nmm/huge_memory.c:4942:void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)\nmm/huge_memory.c-4943-{\n--\nmm/huge_memory.c-5002-\tupdate_mmu_cache_pmd(vma, address, pvmw-\u003epmd);\nmm/huge_memory.c:5003:\ttrace_remove_migration_pmd(address, pmd_val(pmde));\nmm/huge_memory.c-5004-}\n--\nmm/migrate.c=346=static bool remove_migration_pte(struct folio *folio,\n--\nmm/migrate.c-369-\t\t\t\t\t!folio_test_pmd_mappable(folio), folio);\nmm/migrate.c:370:\t\t\tremove_migration_pmd(\u0026pvmw, new);\nmm/migrate.c-371-\t\t\tcontinue;\n"
}

47/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 29377
							output: 27
							thoughts: 33
						

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

**Reaching the Migration Point**

Alright, so `remove_migration_pmd` is definitely reachable. I've confirmed that pathway. Now, my focus shifts to the `migrate_vma_insert_huge_pmd_page` function. I need to understand its behavior in the context of this migration. Specifically, I need to dig into how it interacts with the huge PMD insertion. I expect there is some interplay here that I'll have to fully grasp. This is where the core logic will likely reside, and understanding how these functions interact is crucial.



48/2 2026/07/01 00:14 tool grepper
0m Args:
{
  "Expression": "migrate_vma_insert_huge_pmd_page"
}

Results:
{
  "Output": "mm/migrate_device.c=772=EXPORT_SYMBOL(migrate_vma_setup);\n--\nmm/migrate_device.c-775-/**\nmm/migrate_device.c:776: * migrate_vma_insert_huge_pmd_page: Insert a huge folio into @migrate-\u003evma-\u003evm_mm\nmm/migrate_device.c-777- * at @addr. folio is already allocated as a part of the migration process with\n--\nmm/migrate_device.c-789- */\nmm/migrate_device.c:790:static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,\nmm/migrate_device.c-791-\t\t\t\t\t unsigned long addr,\n--\nmm/migrate_device.c=904=static int migrate_vma_split_unmapped_folio(struct migrate_vma *migrate,\n--\nmm/migrate_device.c-929-#else /* !CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF */\nmm/migrate_device.c:930:static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate,\nmm/migrate_device.c-931-\t\t\t\t\t unsigned long addr,\n--\nmm/migrate_device.c=968=static void migrate_vma_insert_page(struct migrate_vma *migrate,\n--\nmm/migrate_device.c-1002-\tif (thp_migration_supported() \u0026\u0026 (*dst \u0026 MIGRATE_PFN_COMPOUND)) {\nmm/migrate_device.c:1003:\t\tint ret = migrate_vma_insert_huge_pmd_page(migrate, addr, page,\nmm/migrate_device.c-1004-\t\t\t\t\t\t\t\tsrc, pmdp);\n"
}

49/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 30027
							output: 23
							thoughts: 20
						

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

**Assessing Reachability**

Okay, I've got it. Yes, this is definitely something I can work with; the problem is reachable.

Now, let's dive into the specifics and see what's actually going on. My gut feeling is that the key area to examine is `mm_prepare_for_swap_entries`. Let's focus our attention there.



50/2 2026/07/01 00:14 tool grepper
0m Args:
{
  "Expression": "mm_prepare_for_swap_entries"
}

Results:
{
  "Output": "mm/internal.h=1956=bool may_expand_vm(struct mm_struct *mm, const vma_flags_t *vma_flags,\n--\nmm/internal.h-1961- */\nmm/internal.h:1962:static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)\nmm/internal.h-1963-{\n--\nmm/memory.c=941=copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,\n--\nmm/memory.c-955-\nmm/memory.c:956:\t\tmm_prepare_for_swap_entries(dst_mm);\nmm/memory.c-957-\t\t/* Mark the swap entry as shared. */\n--\nmm/rmap.c=1984=static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,\n--\nmm/rmap.c-2306-\t\t\t}\nmm/rmap.c:2307:\t\t\tmm_prepare_for_swap_entries(mm);\nmm/rmap.c-2308-\t\t\tdec_mm_counter(mm, MM_ANONPAGES);\n"
}

51/2 2026/07/01 00:14 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 30481
							output: 289
							thoughts: 872
						

Thoughts:
**My Analysis of the THP Migration and Device Memory Changes**

Okay, reachable. Let's dig into this. My initial focus is on the key symbols related to Transparent Huge Pages (THP) migration and device memory management. I've identified the following:

*   `pagemap_pmd_range_thp`
*   `migrate_vma_collect_huge_pmd`
*   `change_non_present_huge_pmd`
*   `set_pmd_migration_entry`
*   `remove_migration_pmd`
*   `migrate_vma_insert_huge_pmd_page`

I initially considered `mm_prepare_for_swap_entries`, but since it's a static inline function, it's probably not the best focus point. I also excluded `try_to_unmap_one` and `copy_nonpresent_pte` because they are very hot path functions and would likely just muddy the water.

Now, let's verify these remaining symbols aren't static inline. Checking each one, they all seem to be either static within the file, or exported globally. Perfect.

Next, I need to understand the relevant configurations. My understanding so far suggests the following are crucial:

*   `TRANSPARENT_HUGEPAGE`
*   `ZONE_DEVICE`
*   `DEVICE_PRIVATE`
*   `TEST_HMM`

I did a sanity check and saw that `DEVICE_MIGRATION` is automatically enabled when `ZONE_DEVICE` is set. Also, `HMM_MIRROR` is selected by `TEST_HMM`.

I also confirmed that `CONFIG_MIGRATION` is enabled if `NUMA` or `COMPACTION` are enabled, and `CONFIG_MMU` is enabled by default. I noticed `CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF` is selected by `TRANSPARENT_HUGEPAGE`, which is good to know.

Now, looking at the bigger picture. The patch renames `CONFIG_ARCH_ENABLE_THP_MIGRATION` to `CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF` and introduces the new functions `softleaf_to_pmd` and `softleaf_from_pmd` to deal with softleaf entries. This is significant. It also aims to fix potential bugs that might occur when `softleaf_to_page` or `softleaf_to_folio` is called on entries without a PFN or non-device-private entries. This means there's a correction of improper THP migration, particularly related to how these pages are handled. Lastly, the inclusion of `mm_prepare_for_swap_entries` ensures that the `mm` structure is on `init_mm.mmlist` before swap entries are added. This seems like a critical piece to ensure the `mm` structure is initialized before swap entries are added.

So overall, this seems like a solid series of functional changes and refactoring, improving memory management, THP migration, and potentially device memory migration.



52/2 2026/07/01 00:15 tool set-results
0m Args:
{
  "EnableConfigs": [
    "TRANSPARENT_HUGEPAGE",
    "ZONE_DEVICE",
    "DEVICE_PRIVATE",
    "TEST_HMM"
  ],
  "FocusSymbols": [
    "pagemap_pmd_range_thp",
    "migrate_vma_collect_huge_pmd",
    "change_non_present_huge_pmd",
    "set_pmd_migration_entry",
    "remove_migration_pmd",
    "migrate_vma_insert_huge_pmd_page"
  ],
  "Reasoning": "The patch renames CONFIG_ARCH_ENABLE_THP_MIGRATION to CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF and introduces softleaf_to_pmd and softleaf_from_pmd to handle softleaf entries. It also fixes potential bugs where softleaf_to_page or softleaf_to_folio is called on entries without a PFN or non-device-private entries in fs/proc/task_mmu.c and mm/migrate_device.c. It also introduces mm_prepare_for_swap_entries to ensure mm is on init_mm.mmlist before adding swap entries. These are functional changes that affect memory management, THP migration, and device memory migration.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "TRANSPARENT_HUGEPAGE",
    "ZONE_DEVICE",
    "DEVICE_PRIVATE",
    "TEST_HMM"
  ],
  "FocusSymbols": [
    "pagemap_pmd_range_thp",
    "migrate_vma_collect_huge_pmd",
    "change_non_present_huge_pmd",
    "set_pmd_migration_entry",
    "remove_migration_pmd",
    "migrate_vma_insert_huge_pmd_page"
  ],
  "Reasoning": "The patch renames CONFIG_ARCH_ENABLE_THP_MIGRATION to CONFIG_ARCH_SUPPORTS_PMD_SOFTLEAF and introduces softleaf_to_pmd and softleaf_from_pmd to handle softleaf entries. It also fixes potential bugs where softleaf_to_page or softleaf_to_folio is called on entries without a PFN or non-device-private entries in fs/proc/task_mmu.c and mm/migrate_device.c. It also introduces mm_prepare_for_swap_entries to ensure mm is on init_mm.mmlist before adding swap entries. These are functional changes that affect memory management, THP migration, and device memory migration.",
  "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)