| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/16 03:48 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"HUGETLBFS"
],
"FocusSymbols": [
"vmap",
"__vmalloc_node_range_noprof",
"__vmap_pages_range_noflush",
"vmap_pages_range_batched",
"vmap_get_aligned_vm_area",
"vmap_pages_range_noflush_walk",
"vmap_pages_pte_range",
"vmap_pages_pmd_range",
"vmap_pages_pud_range",
"vmap_pages_p4d_range",
"arch_make_huge_pte"
],
"Reasoning": "The patch introduces contiguous PTE mappings for vmalloc on arm64, and updates vmap to support batched mapping for contiguous pages. This modifies core memory management logic and architecture-specific page table manipulation, which are reachable and functional changes.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/16 03:48 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 8d170add4dd1c27842f93ed3bbac44a08667738c\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Jul 16 03:48:54 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/arm64/include/asm/vmalloc.h b/arch/arm64/include/asm/vmalloc.h\nindex 4ec1acd3c1b348..d665f9d687422d 100644\n--- a/arch/arm64/include/asm/vmalloc.h\n+++ b/arch/arm64/include/asm/vmalloc.h\n@@ -23,10 +23,14 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,\n \t\t\t\t\t\tunsigned long end, u64 pfn,\n \t\t\t\t\t\tunsigned int max_page_shift)\n {\n+\tunsigned long size;\n+\n \t/*\n \t * If the block is at least CONT_PTE_SIZE in size, and is naturally\n \t * aligned in both virtual and physical space, then we can pte-map the\n \t * block using the PTE_CONT bit for more efficient use of the TLB.\n+\t * The returned mapping size may cover multiple CONT_PTE_SIZE blocks,\n+\t * capped below PMD_SIZE.\n \t */\n \tif (max_page_shift \u003c CONT_PTE_SHIFT)\n \t\treturn PAGE_SIZE;\n@@ -40,7 +44,9 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,\n \tif (!IS_ALIGNED(PFN_PHYS(pfn), CONT_PTE_SIZE))\n \t\treturn PAGE_SIZE;\n \n-\treturn CONT_PTE_SIZE;\n+\tsize = min3(end - addr, 1UL \u003c\u003c max_page_shift, PMD_SIZE \u003e\u003e 1);\n+\tsize = rounddown_pow_of_two(size);\n+\treturn size;\n }\n \n #define arch_vmap_pte_range_unmap_size arch_vmap_pte_range_unmap_size\ndiff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c\nindex 30772a909aea3e..779d32986d0d67 100644\n--- a/arch/arm64/mm/hugetlbpage.c\n+++ b/arch/arm64/mm/hugetlbpage.c\n@@ -94,6 +94,11 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,\n \treturn CONT_PTES;\n }\n \n+/*\n+ * num_contig_ptes(), set_huge_pte_at() and arch_make_huge_pte() can be\n+ * used by non-hugetlbfs(vmalloc) mm code to set multiple huge mappings\n+ * at the PTE level.\n+ */\n static inline int num_contig_ptes(unsigned long size, size_t *pgsize)\n {\n \tint contig_ptes = 1;\n@@ -110,6 +115,12 @@ static inline int num_contig_ptes(unsigned long size, size_t *pgsize)\n \t\tcontig_ptes = CONT_PTES;\n \t\tbreak;\n \tdefault:\n+\t\tif (size \u003e 0 \u0026\u0026 size \u003c PMD_SIZE \u0026\u0026\n+\t\t\t\tIS_ALIGNED(size, CONT_PTE_SIZE)) {\n+\t\t\t*pgsize = PAGE_SIZE;\n+\t\t\tcontig_ptes = size \u003e\u003e PAGE_SHIFT;\n+\t\t\tbreak;\n+\t\t}\n \t\tWARN_ON(!__hugetlb_valid_size(size));\n \t}\n \n@@ -359,6 +370,10 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\n \tcase CONT_PTE_SIZE:\n \t\treturn pte_mkcont(entry);\n \tdefault:\n+\t\tif (pagesize \u003e 0 \u0026\u0026 pagesize \u003c PMD_SIZE \u0026\u0026\n+\t\t\t\tIS_ALIGNED(pagesize, CONT_PTE_SIZE))\n+\t\t\treturn pte_mkcont(entry);\n+\n \t\tbreak;\n \t}\n \tpr_warn(\"%s: unrecognized huge page size 0x%lx\\n\",\ndiff --git a/mm/vmalloc.c b/mm/vmalloc.c\nindex 1afca3568b9b65..95ffca21946793 100644\n--- a/mm/vmalloc.c\n+++ b/mm/vmalloc.c\n@@ -91,6 +91,33 @@ struct vfree_deferred {\n static DEFINE_PER_CPU(struct vfree_deferred, vfree_deferred);\n \n /*** Page table manipulation functions ***/\n+\n+/*\n+ * Try contiguous mappings at the PTE level for arches which support them, and if\n+ * requested by the caller. Fall back to PAGE_SIZE mappings otherwise.\n+ *\n+ * Return: mapping size.\n+ */\n+static __always_inline unsigned long vmap_set_ptes(pte_t *pte,\n+\t\tunsigned long addr, unsigned long end, u64 pfn,\n+\t\tpgprot_t prot, unsigned int max_page_shift)\n+{\n+#ifdef CONFIG_HUGETLB_PAGE\n+\tunsigned long size;\n+\n+\tsize = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);\n+\tif (size != PAGE_SIZE) {\n+\t\tpte_t entry = pfn_pte(pfn, prot);\n+\n+\t\tentry = arch_make_huge_pte(entry, ilog2(size), 0);\n+\t\tset_huge_pte_at(\u0026init_mm, addr, pte, entry, size);\n+\t\treturn size;\n+\t}\n+#endif\n+\tset_pte_at(\u0026init_mm, addr, pte, pfn_pte(pfn, prot));\n+\treturn PAGE_SIZE;\n+}\n+\n static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,\n \t\t\tphys_addr_t phys_addr, pgprot_t prot,\n \t\t\tunsigned int max_page_shift, pgtbl_mod_mask *mask)\n@@ -98,7 +125,8 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,\n \tpte_t *pte;\n \tu64 pfn;\n \tstruct page *page;\n-\tunsigned long size = PAGE_SIZE;\n+\tunsigned long size;\n+\tunsigned int steps;\n \n \tif (WARN_ON_ONCE(!PAGE_ALIGNED(end - addr)))\n \t\treturn -EINVAL;\n@@ -119,20 +147,9 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,\n \t\t\tBUG();\n \t\t}\n \n-#ifdef CONFIG_HUGETLB_PAGE\n-\t\tsize = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);\n-\t\tif (size != PAGE_SIZE) {\n-\t\t\tpte_t entry = pfn_pte(pfn, prot);\n-\n-\t\t\tentry = arch_make_huge_pte(entry, ilog2(size), 0);\n-\t\t\tset_huge_pte_at(\u0026init_mm, addr, pte, entry, size);\n-\t\t\tpfn += PFN_DOWN(size);\n-\t\t\tcontinue;\n-\t\t}\n-#endif\n-\t\tset_pte_at(\u0026init_mm, addr, pte, pfn_pte(pfn, prot));\n-\t\tpfn++;\n-\t} while (pte += PFN_DOWN(size), addr += size, addr != end);\n+\t\tsize = vmap_set_ptes(pte, addr, end, pfn, prot, max_page_shift);\n+\t\tsteps = PFN_DOWN(size);\n+\t} while (pte += steps, pfn += steps, addr += size, addr != end);\n \n \tlazy_mmu_mode_disable();\n \t*mask |= PGTBL_PTE_MODIFIED;\n@@ -524,8 +541,10 @@ void vunmap_range(unsigned long addr, unsigned long end)\n \n static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,\n \t\tunsigned long end, pgprot_t prot, struct page **pages, int *nr,\n-\t\tpgtbl_mod_mask *mask)\n+\t\tpgtbl_mod_mask *mask, unsigned int shift)\n {\n+\tunsigned long pfn, size;\n+\tunsigned int steps;\n \tint err = 0;\n \tpte_t *pte;\n \n@@ -556,9 +575,10 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,\n \t\t\tbreak;\n \t\t}\n \n-\t\tset_pte_at(\u0026init_mm, addr, pte, mk_pte(page, prot));\n-\t\t(*nr)++;\n-\t} while (pte++, addr += PAGE_SIZE, addr != end);\n+\t\tpfn = page_to_pfn(page);\n+\t\tsize = vmap_set_ptes(pte, addr, end, pfn, prot, shift);\n+\t\tsteps = PFN_DOWN(size);\n+\t} while (pte += steps, *nr += steps, addr += size, addr != end);\n \n \tlazy_mmu_mode_disable();\n \t*mask |= PGTBL_PTE_MODIFIED;\n@@ -568,60 +588,90 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,\n \n static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,\n \t\tunsigned long end, pgprot_t prot, struct page **pages, int *nr,\n-\t\tpgtbl_mod_mask *mask)\n+\t\tpgtbl_mod_mask *mask, unsigned int shift)\n {\n \tpmd_t *pmd;\n \tunsigned long next;\n+\tint err;\n \n \tpmd = pmd_alloc_track(\u0026init_mm, pud, addr, mask);\n \tif (!pmd)\n \t\treturn -ENOMEM;\n \tdo {\n \t\tnext = pmd_addr_end(addr, end);\n-\t\tif (vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask))\n-\t\t\treturn -ENOMEM;\n+\n+\t\tif (shift \u003e= PMD_SHIFT) {\n+\t\t\tstruct page *page = pages[*nr];\n+\t\t\tphys_addr_t phys_addr;\n+\n+\t\t\tif (WARN_ON(!page))\n+\t\t\t\treturn -ENOMEM;\n+\t\t\tif (WARN_ON(!pfn_valid(page_to_pfn(page))))\n+\t\t\t\treturn -EINVAL;\n+\n+\t\t\tphys_addr = page_to_phys(page);\n+\n+\t\t\tif (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot,\n+\t\t\t\t\t\tshift)) {\n+\t\t\t\t*mask |= PGTBL_PMD_MODIFIED;\n+\t\t\t\t*nr += 1 \u003c\u003c (PMD_SHIFT - PAGE_SHIFT);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n+\t\terr = vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask, shift);\n+\t\tif (err)\n+\t\t\treturn err;\n \t} while (pmd++, addr = next, addr != end);\n \treturn 0;\n }\n \n static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,\n \t\tunsigned long end, pgprot_t prot, struct page **pages, int *nr,\n-\t\tpgtbl_mod_mask *mask)\n+\t\tpgtbl_mod_mask *mask, unsigned int shift)\n {\n \tpud_t *pud;\n \tunsigned long next;\n+\tint err;\n \n \tpud = pud_alloc_track(\u0026init_mm, p4d, addr, mask);\n \tif (!pud)\n \t\treturn -ENOMEM;\n \tdo {\n \t\tnext = pud_addr_end(addr, end);\n-\t\tif (vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask))\n-\t\t\treturn -ENOMEM;\n+\t\terr = vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask, shift);\n+\t\tif (err)\n+\t\t\treturn err;\n \t} while (pud++, addr = next, addr != end);\n \treturn 0;\n }\n \n static int vmap_pages_p4d_range(pgd_t *pgd, unsigned long addr,\n \t\tunsigned long end, pgprot_t prot, struct page **pages, int *nr,\n-\t\tpgtbl_mod_mask *mask)\n+\t\tpgtbl_mod_mask *mask, unsigned int shift)\n {\n \tp4d_t *p4d;\n \tunsigned long next;\n+\tint err;\n \n \tp4d = p4d_alloc_track(\u0026init_mm, pgd, addr, mask);\n \tif (!p4d)\n \t\treturn -ENOMEM;\n \tdo {\n \t\tnext = p4d_addr_end(addr, end);\n-\t\tif (vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask))\n-\t\t\treturn -ENOMEM;\n+\t\terr = vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask, shift);\n+\t\tif (err)\n+\t\t\treturn err;\n \t} while (p4d++, addr = next, addr != end);\n \treturn 0;\n }\n \n-static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,\n-\t\tpgprot_t prot, struct page **pages)\n+/*\n+ * It can take an array of pages which are not all contiguous, but it\n+ * may have contiguous chunks, as hinted by @shift.\n+ */\n+static int vmap_pages_range_noflush_walk(unsigned long addr, unsigned long end,\n+\t\tpgprot_t prot, struct page **pages, unsigned int shift)\n {\n \tunsigned long start = addr;\n \tpgd_t *pgd;\n@@ -636,7 +686,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,\n \t\tnext = pgd_addr_end(addr, end);\n \t\tif (pgd_bad(*pgd))\n \t\t\tmask |= PGTBL_PGD_MODIFIED;\n-\t\terr = vmap_pages_p4d_range(pgd, addr, next, prot, pages, \u0026nr, \u0026mask);\n+\t\terr = vmap_pages_p4d_range(pgd, addr, next, prot, pages, \u0026nr, \u0026mask, shift);\n \t\tif (err)\n \t\t\tbreak;\n \t} while (pgd++, addr = next, addr != end);\n@@ -659,27 +709,12 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,\n int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,\n \t\tpgprot_t prot, struct page **pages, unsigned int page_shift)\n {\n-\tunsigned int i, nr = (end - addr) \u003e\u003e PAGE_SHIFT;\n-\n \tWARN_ON(page_shift \u003c PAGE_SHIFT);\n \n-\tif (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC) ||\n-\t\t\tpage_shift == PAGE_SHIFT)\n-\t\treturn vmap_small_pages_range_noflush(addr, end, prot, pages);\n-\n-\tfor (i = 0; i \u003c nr; i += 1U \u003c\u003c (page_shift - PAGE_SHIFT)) {\n-\t\tint err;\n-\n-\t\terr = vmap_range_noflush(addr, addr + (1UL \u003c\u003c page_shift),\n-\t\t\t\t\tpage_to_phys(pages[i]), prot,\n-\t\t\t\t\tpage_shift);\n-\t\tif (err)\n-\t\t\treturn err;\n-\n-\t\taddr += 1UL \u003c\u003c page_shift;\n-\t}\n+\tif (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC))\n+\t\tpage_shift = PAGE_SHIFT;\n \n-\treturn 0;\n+\treturn vmap_pages_range_noflush_walk(addr, end, prot, pages, page_shift);\n }\n \n int vmap_pages_range_noflush(unsigned long addr, unsigned long end,\n@@ -3279,6 +3314,14 @@ struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,\n \t\t\t\t NUMA_NO_NODE, GFP_KERNEL, caller);\n }\n \n+static struct vm_struct *__get_vm_area_node_aligned_caller(unsigned long size,\n+\t\tunsigned long align, unsigned long flags, const void *caller)\n+{\n+\treturn __get_vm_area_node(size, align, PAGE_SHIFT, flags,\n+\t\t\t\t VMALLOC_START, VMALLOC_END,\n+\t\t\t\t NUMA_NO_NODE, GFP_KERNEL, caller);\n+}\n+\n /**\n * find_vm_area - find a continuous kernel virtual area\n * @addr:\t base address\n@@ -3519,6 +3562,116 @@ void vunmap(const void *addr)\n }\n EXPORT_SYMBOL(vunmap);\n \n+static inline unsigned int vm_shift(pgprot_t prot, unsigned long size)\n+{\n+\tif (arch_vmap_pmd_supported(prot) \u0026\u0026 size \u003e= PMD_SIZE)\n+\t\treturn PMD_SHIFT;\n+\n+\treturn arch_vmap_pte_supported_shift(size);\n+}\n+\n+static inline int get_vmap_batch_order(struct page **pages,\n+\t\tpgprot_t prot, unsigned int max_steps, unsigned int idx)\n+{\n+\tunsigned long pfn;\n+\tunsigned int nr_contig;\n+\tint order;\n+\n+\tif (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))\n+\t\treturn 0;\n+\n+\tnr_contig = num_pages_contiguous(\u0026pages[idx], max_steps);\n+\tif (nr_contig \u003c 2)\n+\t\treturn 0;\n+\n+\torder = ilog2(nr_contig);\n+\tpfn = page_to_pfn(pages[idx]);\n+\n+\t/* Limit order by pfn alignment */\n+\tif (pfn \u003e 0)\n+\t\torder = min_t(int, order, __ffs(pfn));\n+\n+\tif (vm_shift(prot, PAGE_SIZE \u003c\u003c order) == PAGE_SHIFT)\n+\t\treturn 0;\n+\n+\treturn order;\n+}\n+\n+static int vmap_pages_range_batched(unsigned long addr, unsigned long end,\n+\t\tpgprot_t prot, struct page **pages)\n+{\n+\tunsigned int count = (end - addr) \u003e\u003e PAGE_SHIFT;\n+\tunsigned int prev_shift = 0, idx = 0;\n+\tunsigned long map_addr = addr, batch_end = addr;\n+\tint err;\n+\n+\terr = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,\n+\t\t\t\t\t PAGE_SHIFT, GFP_KERNEL);\n+\tif (err)\n+\t\tgoto out;\n+\n+\tfor (unsigned int i = 0; i \u003c count; ) {\n+\t\tunsigned int shift = PAGE_SHIFT +\n+\t\t\tget_vmap_batch_order(pages, prot, count - i, i);\n+\n+\t\tif (!i)\n+\t\t\tprev_shift = shift;\n+\n+\t\tif (shift != prev_shift) {\n+\t\t\terr = vmap_pages_range_noflush_walk(map_addr, batch_end,\n+\t\t\t\t\tprot, pages + idx, prev_shift);\n+\t\t\tif (err)\n+\t\t\t\tgoto out;\n+\t\t\tprev_shift = shift;\n+\t\t\tmap_addr = batch_end;\n+\t\t\tidx = i;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Once small pages are encountered, the remaining pages\n+\t\t * are likely small as well.\n+\t\t */\n+\t\tif (shift == PAGE_SHIFT)\n+\t\t\tbreak;\n+\n+\t\tbatch_end += 1UL \u003c\u003c shift;\n+\t\ti += 1U \u003c\u003c (shift - PAGE_SHIFT);\n+\t}\n+\n+\t/* Remaining */\n+\tif (map_addr \u003c end)\n+\t\terr = vmap_pages_range_noflush_walk(map_addr, end,\n+\t\t\t\tprot, pages + idx, prev_shift);\n+\n+out:\n+\tflush_cache_vmap(addr, end);\n+\treturn err;\n+}\n+\n+static struct vm_struct *vmap_get_aligned_vm_area(unsigned long size,\n+\t\tunsigned long flags, pgprot_t prot, const void *caller)\n+{\n+\tstruct vm_struct *vm_area;\n+\tunsigned int shift;\n+\n+\tif (arch_vmap_pmd_supported(prot) \u0026\u0026 size \u003e= PMD_SIZE) {\n+\t\tvm_area = __get_vm_area_node_aligned_caller(size, PMD_SIZE,\n+\t\t\t\tflags, caller);\n+\t\tif (vm_area)\n+\t\t\treturn vm_area;\n+\t}\n+\n+\tshift = arch_vmap_pte_supported_shift(size);\n+\tif (shift \u003e PAGE_SHIFT) {\n+\t\tvm_area = __get_vm_area_node_aligned_caller(size, 1UL \u003c\u003c shift,\n+\t\t\t\tflags, caller);\n+\t\tif (vm_area)\n+\t\t\treturn vm_area;\n+\t}\n+\n+\treturn __get_vm_area_node_aligned_caller(size, PAGE_SIZE, flags, caller);\n+}\n+\n /**\n * vmap - map an array of pages into virtually contiguous space\n * @pages: array of page pointers\n@@ -3557,13 +3710,14 @@ void *vmap(struct page **pages, unsigned int count,\n \t\treturn NULL;\n \n \tsize = (unsigned long)count \u003c\u003c PAGE_SHIFT;\n-\tarea = get_vm_area_caller(size, flags, __builtin_return_address(0));\n+\tarea = vmap_get_aligned_vm_area(size, flags, prot,\n+\t\t\t\t__builtin_return_address(0));\n \tif (!area)\n \t\treturn NULL;\n \n \taddr = (unsigned long)area-\u003eaddr;\n-\tif (vmap_pages_range(addr, addr + size, pgprot_nx(prot),\n-\t\t\t\tpages, PAGE_SHIFT) \u003c 0) {\n+\tif (vmap_pages_range_batched(addr, addr + size, pgprot_nx(prot),\n+\t\t\t\tpages) \u003c 0) {\n \t\tvunmap(area-\u003eaddr);\n \t\treturn NULL;\n \t}\n@@ -4030,11 +4184,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,\n \t\t * supporting them.\n \t\t */\n \n-\t\tif (arch_vmap_pmd_supported(prot) \u0026\u0026 size \u003e= PMD_SIZE)\n-\t\t\tshift = PMD_SHIFT;\n-\t\telse\n-\t\t\tshift = arch_vmap_pte_supported_shift(size);\n-\n+\t\tshift = vm_shift(prot, size);\n \t\talign = max(original_align, 1UL \u003c\u003c shift);\n \t}\n \n"
} |
| 2/1 | 2026/07/16 03:48 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"HUGETLBFS"
],
"FocusSymbols": [
"vmap",
"__vmalloc_node_range_noprof",
"__vmap_pages_range_noflush",
"vmap_pages_range_batched",
"vmap_get_aligned_vm_area",
"vmap_pages_range_noflush_walk",
"vmap_pages_pte_range",
"vmap_pages_pmd_range",
"vmap_pages_pud_range",
"vmap_pages_p4d_range",
"arch_make_huge_pte"
],
"Reasoning": "The patch introduces contiguous PTE mappings for vmalloc on arm64, and updates vmap to support batched mapping for contiguous pages. This modifies core memory management logic and architecture-specific page table manipulation, which are reachable and functional changes.",
"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 8d170add4dd1c27842f93ed3bbac44a08667738c
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Jul 16 03:48:54 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/arm64/include/asm/vmalloc.h b/arch/arm64/include/asm/vmalloc.h
index 4ec1acd3c1b348..d665f9d687422d 100644
--- a/arch/arm64/include/asm/vmalloc.h
+++ b/arch/arm64/include/asm/vmalloc.h
@@ -23,10 +23,14 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,
unsigned long end, u64 pfn,
unsigned int max_page_shift)
{
+ unsigned long size;
+
/*
* If the block is at least CONT_PTE_SIZE in size, and is naturally
* aligned in both virtual and physical space, then we can pte-map the
* block using the PTE_CONT bit for more efficient use of the TLB.
+ * The returned mapping size may cover multiple CONT_PTE_SIZE blocks,
+ * capped below PMD_SIZE.
*/
if (max_page_shift < CONT_PTE_SHIFT)
return PAGE_SIZE;
@@ -40,7 +44,9 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,
if (!IS_ALIGNED(PFN_PHYS(pfn), CONT_PTE_SIZE))
return PAGE_SIZE;
- return CONT_PTE_SIZE;
+ size = min3(end - addr, 1UL << max_page_shift, PMD_SIZE >> 1);
+ size = rounddown_pow_of_two(size);
+ return size;
}
#define arch_vmap_pte_range_unmap_size arch_vmap_pte_range_unmap_size
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 30772a909aea3e..779d32986d0d67 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -94,6 +94,11 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
return CONT_PTES;
}
+/*
+ * num_contig_ptes(), set_huge_pte_at() and arch_make_huge_pte() can be
+ * used by non-hugetlbfs(vmalloc) mm code to set multiple huge mappings
+ * at the PTE level.
+ */
static inline int num_contig_ptes(unsigned long size, size_t *pgsize)
{
int contig_ptes = 1;
@@ -110,6 +115,12 @@ static inline int num_contig_ptes(unsigned long size, size_t *pgsize)
contig_ptes = CONT_PTES;
break;
default:
+ if (size > 0 && size < PMD_SIZE &&
+ IS_ALIGNED(size, CONT_PTE_SIZE)) {
+ *pgsize = PAGE_SIZE;
+ contig_ptes = size >> PAGE_SHIFT;
+ break;
+ }
WARN_ON(!__hugetlb_valid_size(size));
}
@@ -359,6 +370,10 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
case CONT_PTE_SIZE:
return pte_mkcont(entry);
default:
+ if (pagesize > 0 && pagesize < PMD_SIZE &&
+ IS_ALIGNED(pagesize, CONT_PTE_SIZE))
+ return pte_mkcont(entry);
+
break;
}
pr_warn("%s: unrecognized huge page size 0x%lx\n",
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 1afca3568b9b65..95ffca21946793 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -91,6 +91,33 @@ struct vfree_deferred {
static DEFINE_PER_CPU(struct vfree_deferred, vfree_deferred);
/*** Page table manipulation functions ***/
+
+/*
+ * Try contiguous mappings at the PTE level for arches which support them, and if
+ * requested by the caller. Fall back to PAGE_SIZE mappings otherwise.
+ *
+ * Return: mapping size.
+ */
+static __always_inline unsigned long vmap_set_ptes(pte_t *pte,
+ unsigned long addr, unsigned long end, u64 pfn,
+ pgprot_t prot, unsigned int max_page_shift)
+{
+#ifdef CONFIG_HUGETLB_PAGE
+ unsigned long size;
+
+ size = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);
+ if (size != PAGE_SIZE) {
+ pte_t entry = pfn_pte(pfn, prot);
+
+ entry = arch_make_huge_pte(entry, ilog2(size), 0);
+ set_huge_pte_at(&init_mm, addr, pte, entry, size);
+ return size;
+ }
+#endif
+ set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
+ return PAGE_SIZE;
+}
+
static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
phys_addr_t phys_addr, pgprot_t prot,
unsigned int max_page_shift, pgtbl_mod_mask *mask)
@@ -98,7 +125,8 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
pte_t *pte;
u64 pfn;
struct page *page;
- unsigned long size = PAGE_SIZE;
+ unsigned long size;
+ unsigned int steps;
if (WARN_ON_ONCE(!PAGE_ALIGNED(end - addr)))
return -EINVAL;
@@ -119,20 +147,9 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
BUG();
}
-#ifdef CONFIG_HUGETLB_PAGE
- size = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);
- if (size != PAGE_SIZE) {
- pte_t entry = pfn_pte(pfn, prot);
-
- entry = arch_make_huge_pte(entry, ilog2(size), 0);
- set_huge_pte_at(&init_mm, addr, pte, entry, size);
- pfn += PFN_DOWN(size);
- continue;
- }
-#endif
- set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
- pfn++;
- } while (pte += PFN_DOWN(size), addr += size, addr != end);
+ size = vmap_set_ptes(pte, addr, end, pfn, prot, max_page_shift);
+ steps = PFN_DOWN(size);
+ } while (pte += steps, pfn += steps, addr += size, addr != end);
lazy_mmu_mode_disable();
*mask |= PGTBL_PTE_MODIFIED;
@@ -524,8 +541,10 @@ void vunmap_range(unsigned long addr, unsigned long end)
static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
+ unsigned long pfn, size;
+ unsigned int steps;
int err = 0;
pte_t *pte;
@@ -556,9 +575,10 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
break;
}
- set_pte_at(&init_mm, addr, pte, mk_pte(page, prot));
- (*nr)++;
- } while (pte++, addr += PAGE_SIZE, addr != end);
+ pfn = page_to_pfn(page);
+ size = vmap_set_ptes(pte, addr, end, pfn, prot, shift);
+ steps = PFN_DOWN(size);
+ } while (pte += steps, *nr += steps, addr += size, addr != end);
lazy_mmu_mode_disable();
*mask |= PGTBL_PTE_MODIFIED;
@@ -568,60 +588,90 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
pmd_t *pmd;
unsigned long next;
+ int err;
pmd = pmd_alloc_track(&init_mm, pud, addr, mask);
if (!pmd)
return -ENOMEM;
do {
next = pmd_addr_end(addr, end);
- if (vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask))
- return -ENOMEM;
+
+ if (shift >= PMD_SHIFT) {
+ struct page *page = pages[*nr];
+ phys_addr_t phys_addr;
+
+ if (WARN_ON(!page))
+ return -ENOMEM;
+ if (WARN_ON(!pfn_valid(page_to_pfn(page))))
+ return -EINVAL;
+
+ phys_addr = page_to_phys(page);
+
+ if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot,
+ shift)) {
+ *mask |= PGTBL_PMD_MODIFIED;
+ *nr += 1 << (PMD_SHIFT - PAGE_SHIFT);
+ continue;
+ }
+ }
+
+ err = vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask, shift);
+ if (err)
+ return err;
} while (pmd++, addr = next, addr != end);
return 0;
}
static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
pud_t *pud;
unsigned long next;
+ int err;
pud = pud_alloc_track(&init_mm, p4d, addr, mask);
if (!pud)
return -ENOMEM;
do {
next = pud_addr_end(addr, end);
- if (vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask))
- return -ENOMEM;
+ err = vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask, shift);
+ if (err)
+ return err;
} while (pud++, addr = next, addr != end);
return 0;
}
static int vmap_pages_p4d_range(pgd_t *pgd, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
p4d_t *p4d;
unsigned long next;
+ int err;
p4d = p4d_alloc_track(&init_mm, pgd, addr, mask);
if (!p4d)
return -ENOMEM;
do {
next = p4d_addr_end(addr, end);
- if (vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask))
- return -ENOMEM;
+ err = vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask, shift);
+ if (err)
+ return err;
} while (p4d++, addr = next, addr != end);
return 0;
}
-static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
- pgprot_t prot, struct page **pages)
+/*
+ * It can take an array of pages which are not all contiguous, but it
+ * may have contiguous chunks, as hinted by @shift.
+ */
+static int vmap_pages_range_noflush_walk(unsigned long addr, unsigned long end,
+ pgprot_t prot, struct page **pages, unsigned int shift)
{
unsigned long start = addr;
pgd_t *pgd;
@@ -636,7 +686,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
next = pgd_addr_end(addr, end);
if (pgd_bad(*pgd))
mask |= PGTBL_PGD_MODIFIED;
- err = vmap_pages_p4d_range(pgd, addr, next, prot, pages, &nr, &mask);
+ err = vmap_pages_p4d_range(pgd, addr, next, prot, pages, &nr, &mask, shift);
if (err)
break;
} while (pgd++, addr = next, addr != end);
@@ -659,27 +709,12 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
pgprot_t prot, struct page **pages, unsigned int page_shift)
{
- unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
-
WARN_ON(page_shift < PAGE_SHIFT);
- if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC) ||
- page_shift == PAGE_SHIFT)
- return vmap_small_pages_range_noflush(addr, end, prot, pages);
-
- for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
- int err;
-
- err = vmap_range_noflush(addr, addr + (1UL << page_shift),
- page_to_phys(pages[i]), prot,
- page_shift);
- if (err)
- return err;
-
- addr += 1UL << page_shift;
- }
+ if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC))
+ page_shift = PAGE_SHIFT;
- return 0;
+ return vmap_pages_range_noflush_walk(addr, end, prot, pages, page_shift);
}
int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
@@ -3279,6 +3314,14 @@ struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
NUMA_NO_NODE, GFP_KERNEL, caller);
}
+static struct vm_struct *__get_vm_area_node_aligned_caller(unsigned long size,
+ unsigned long align, unsigned long flags, const void *caller)
+{
+ return __get_vm_area_node(size, align, PAGE_SHIFT, flags,
+ VMALLOC_START, VMALLOC_END,
+ NUMA_NO_NODE, GFP_KERNEL, caller);
+}
+
/**
* find_vm_area - find a continuous kernel virtual area
* @addr: base address
@@ -3519,6 +3562,116 @@ void vunmap(const void *addr)
}
EXPORT_SYMBOL(vunmap);
+static inline unsigned int vm_shift(pgprot_t prot, unsigned long size)
+{
+ if (arch_vmap_pmd_supported(prot) && size >= PMD_SIZE)
+ return PMD_SHIFT;
+
+ return arch_vmap_pte_supported_shift(size);
+}
+
+static inline int get_vmap_batch_order(struct page **pages,
+ pgprot_t prot, unsigned int max_steps, unsigned int idx)
+{
+ unsigned long pfn;
+ unsigned int nr_contig;
+ int order;
+
+ if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
+ return 0;
+
+ nr_contig = num_pages_contiguous(&pages[idx], max_steps);
+ if (nr_contig < 2)
+ return 0;
+
+ order = ilog2(nr_contig);
+ pfn = page_to_pfn(pages[idx]);
+
+ /* Limit order by pfn alignment */
+ if (pfn > 0)
+ order = min_t(int, order, __ffs(pfn));
+
+ if (vm_shift(prot, PAGE_SIZE << order) == PAGE_SHIFT)
+ return 0;
+
+ return order;
+}
+
+static int vmap_pages_range_batched(unsigned long addr, unsigned long end,
+ pgprot_t prot, struct page **pages)
+{
+ unsigned int count = (end - addr) >> PAGE_SHIFT;
+ unsigned int prev_shift = 0, idx = 0;
+ unsigned long map_addr = addr, batch_end = addr;
+ int err;
+
+ err = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,
+ PAGE_SHIFT, GFP_KERNEL);
+ if (err)
+ goto out;
+
+ for (unsigned int i = 0; i < count; ) {
+ unsigned int shift = PAGE_SHIFT +
+ get_vmap_batch_order(pages, prot, count - i, i);
+
+ if (!i)
+ prev_shift = shift;
+
+ if (shift != prev_shift) {
+ err = vmap_pages_range_noflush_walk(map_addr, batch_end,
+ prot, pages + idx, prev_shift);
+ if (err)
+ goto out;
+ prev_shift = shift;
+ map_addr = batch_end;
+ idx = i;
+ }
+
+ /*
+ * Once small pages are encountered, the remaining pages
+ * are likely small as well.
+ */
+ if (shift == PAGE_SHIFT)
+ break;
+
+ batch_end += 1UL << shift;
+ i += 1U << (shift - PAGE_SHIFT);
+ }
+
+ /* Remaining */
+ if (map_addr < end)
+ err = vmap_pages_range_noflush_walk(map_addr, end,
+ prot, pages + idx, prev_shift);
+
+out:
+ flush_cache_vmap(addr, end);
+ return err;
+}
+
+static struct vm_struct *vmap_get_aligned_vm_area(unsigned long size,
+ unsigned long flags, pgprot_t prot, const void *caller)
+{
+ struct vm_struct *vm_area;
+ unsigned int shift;
+
+ if (arch_vmap_pmd_supported(prot) && size >= PMD_SIZE) {
+ vm_area = __get_vm_area_node_aligned_caller(size, PMD_SIZE,
+ flags, caller);
+ if (vm_area)
+ return vm_area;
+ }
+
+ shift = arch_vmap_pte_supported_shift(size);
+ if (shift > PAGE_SHIFT) {
+ vm_area = __get_vm_area_node_aligned_caller(size, 1UL << shift,
+ flags, caller);
+ if (vm_area)
+ return vm_area;
+ }
+
+ return __get_vm_area_node_aligned_caller(size, PAGE_SIZE, flags, caller);
+}
+
/**
* vmap - map an array of pages into virtually contiguous space
* @pages: array of page pointers
@@ -3557,13 +3710,14 @@ void *vmap(struct page **pages, unsigned int count,
return NULL;
size = (unsigned long)count << PAGE_SHIFT;
- area = get_vm_area_caller(size, flags, __builtin_return_address(0));
+ area = vmap_get_aligned_vm_area(size, flags, prot,
+ __builtin_return_address(0));
if (!area)
return NULL;
addr = (unsigned long)area->addr;
- if (vmap_pages_range(addr, addr + size, pgprot_nx(prot),
- pages, PAGE_SHIFT) < 0) {
+ if (vmap_pages_range_batched(addr, addr + size, pgprot_nx(prot),
+ pages) < 0) {
vunmap(area->addr);
return NULL;
}
@@ -4030,11 +4184,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
* supporting them.
*/
- if (arch_vmap_pmd_supported(prot) && size >= PMD_SIZE)
- shift = PMD_SHIFT;
- else
- shift = arch_vmap_pte_supported_shift(size);
-
+ shift = vm_shift(prot, size);
align = max(original_align, 1UL << shift);
}
|
| 3/2 | 2026/07/16 03:48 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7490 output: 24 thoughts: 463 Thoughts: **Analyzing a Patch for Contiguous PTE Mappings in vmalloc on arm64** Okay, so I'm looking at this patch and it's making some pretty significant changes. It looks like it's trying to introduce contiguous PTE mappings for vmalloc on arm64, which is interesting. The changes are spread across `arch/arm64/include/asm/vmalloc.h`, `arch/arm64/mm/hugetlbpage.c`, and `mm/vmalloc.c`, so it's touching quite a few areas. From what I can tell, the core of the change seems to be around extending `vmap` to handle batched mappings for contiguous pages. It's modifying `arch_vmap_pte_range_map_size` to handle sizes up to the PMD boundary, and it looks like it's been updated to take in multiple `CONT_PTE_SIZE` blocks. There are also updates to `num_contig_ptes` and `arch_make_huge_pte` to support sizes within a given range that are aligned to `CONT_PTE_SIZE`. In `mm/vmalloc.c`, the patch seems to add a function called `vmap_set_ptes` that leverages the updated `arch_vmap_pte_range_map_size` and `arch_make_huge_pte` to set multiple PTEs at once, which is where the batching comes into play. It appears that it's updating the different range mapping functions, such as `vmap_pages_pte_range`, `vmap_pages_pmd_range`, and so on, to accept a shift parameter and use this new `vmap_set_ptes` function. There are also new functions, `vmap_pages_range_batched` and `vmap_get_aligned_vm_area`, that seem to be key components of this new batching functionality, being used in `vmap`. This is a functional change to the core memory management subsystem, specifically the vmalloc portion, as well as the arm64 architecture implementation. Considering the potential impact on memory allocation, I'm thinking this is definitely a prime candidate for thorough fuzzing. Before I delve deeper into the code, I should probably check the configuration dependencies. Let's see... `CONFIG_HAVE_ARCH_HUGE_VMALLOC`, `CONFIG_HAVE_ARCH_HUGE_VMAP`, and `CONFIG_HUGETLB_PAGE` are mentioned in `mm/vmalloc.c`. I'll grep `mm/Kconfig` and `arch/arm64/Kconfig` to figure out the exact configuration requirements for this patch. I need to make sure I can build a kernel that will actually run this new code. |
| 4/2 | 2026/07/16 03:49 | tool | grepper |
0mArgs:{
"Expression": "HAVE_ARCH_HUGE_VMALLOC"
}Results: {
"Output": "arch/Kconfig=1092=config HAVE_ARCH_HUGE_VMAP\n--\narch/Kconfig-1099-#\narch/Kconfig:1100:config HAVE_ARCH_HUGE_VMALLOC\narch/Kconfig-1101-\tdepends on HAVE_ARCH_HUGE_VMAP\n--\narch/arm64/Kconfig=2=config ARM64\n--\narch/arm64/Kconfig-153-\tselect HAVE_ARCH_COMPILER_H\narch/arm64/Kconfig:154:\tselect HAVE_ARCH_HUGE_VMALLOC\narch/arm64/Kconfig-155-\tselect HAVE_ARCH_HUGE_VMAP\n--\narch/powerpc/Kconfig=118=config PPC\n--\narch/powerpc/Kconfig-218-\tselect HAVE_ARCH_AUDITSYSCALL\narch/powerpc/Kconfig:219:\tselect HAVE_ARCH_HUGE_VMALLOC\t\tif HAVE_ARCH_HUGE_VMAP\narch/powerpc/Kconfig-220-\tselect HAVE_ARCH_HUGE_VMAP\t\tif PPC_RADIX_MMU || PPC_8xx\n--\narch/riscv/Kconfig=13=config RISCV\n--\narch/riscv/Kconfig-131-\tselect HAVE_ARCH_BITREVERSE if RISCV_ISA_ZBKB \u0026\u0026 BITREVERSE\narch/riscv/Kconfig:132:\tselect HAVE_ARCH_HUGE_VMALLOC if HAVE_ARCH_HUGE_VMAP\narch/riscv/Kconfig-133-\tselect HAVE_ARCH_HUGE_VMAP if MMU \u0026\u0026 64BIT\n--\narch/x86/Kconfig=58=config X86\n--\narch/x86/Kconfig-192-\tselect HAVE_ARCH_HUGE_VMAP\t\tif X86_64 || X86_PAE\narch/x86/Kconfig:193:\tselect HAVE_ARCH_HUGE_VMALLOC\t\tif X86_64\narch/x86/Kconfig-194-\tselect HAVE_ARCH_JUMP_LABEL\n--\ninclude/linux/vmalloc.h=19=struct iov_iter;\t\t/* in uio.h */\n--\ninclude/linux/vmalloc.h-31-#define VM_MAP_PUT_PAGES\t0x00000200\t/* put pages and free array in vfree */\ninclude/linux/vmalloc.h:32:#define VM_ALLOW_HUGE_VMAP\t0x00000400 /* Allow for huge pages on archs with HAVE_ARCH_HUGE_VMALLOC */\ninclude/linux/vmalloc.h-33-\n--\ninclude/linux/vmalloc.h=52=struct vm_struct {\n--\ninclude/linux/vmalloc.h-61-\tstruct page\t\t**pages;\ninclude/linux/vmalloc.h:62:#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC\ninclude/linux/vmalloc.h-63-\tunsigned int\t\tpage_order;\n--\ninclude/linux/vmalloc.h=258=static inline bool is_vm_area_hugepages(const void *addr)\n--\ninclude/linux/vmalloc.h-266-\t */\ninclude/linux/vmalloc.h:267:#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC\ninclude/linux/vmalloc.h-268-\tstruct vm_struct *area = find_vm_area(addr);\n--\nmm/vmalloc.c=63=static const unsigned int ioremap_max_page_shift = PAGE_SHIFT;\n--\nmm/vmalloc.c-65-\nmm/vmalloc.c:66:#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC\nmm/vmalloc.c-67-static bool __ro_after_init vmap_allow_huge = true;\n--\nmm/vmalloc.c=74=early_param(\"nohugevmalloc\", set_nohugevmalloc);\nmm/vmalloc.c:75:#else /* CONFIG_HAVE_ARCH_HUGE_VMALLOC */\nmm/vmalloc.c-76-static const bool vmap_allow_huge = false;\nmm/vmalloc.c:77:#endif\t/* CONFIG_HAVE_ARCH_HUGE_VMALLOC */\nmm/vmalloc.c-78-\n--\nmm/vmalloc.c=709=int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,\n--\nmm/vmalloc.c-713-\nmm/vmalloc.c:714:\tif (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC))\nmm/vmalloc.c-715-\t\tpage_shift = PAGE_SHIFT;\n--\nmm/vmalloc.c=3140=static inline unsigned int vm_area_page_order(struct vm_struct *vm)\nmm/vmalloc.c-3141-{\nmm/vmalloc.c:3142:#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC\nmm/vmalloc.c-3143-\treturn vm-\u003epage_order;\n--\nmm/vmalloc.c=3154=static inline void set_vm_area_page_order(struct vm_struct *vm, unsigned int order)\nmm/vmalloc.c-3155-{\nmm/vmalloc.c:3156:#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC\nmm/vmalloc.c-3157-\tvm-\u003epage_order = order;\n"
} |
| 5/2 | 2026/07/16 03:49 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9960 output: 21 thoughts: 398 Thoughts: **My Analysis of vmap and Related Functions** Okay, so I'm looking at how virtual mappings and potentially huge pages are handled, specifically on `ARM64` and `X86_64` architectures. Since those architectures automatically enable `HAVE_ARCH_HUGE_VMALLOC`, `HAVE_ARCH_HUGE_VMAP`, and `HUGETLB_PAGE`, I can assume those configurations are already baked in. Now, I need to pinpoint the critical functions. Based on the names, `vmap_pages_range_batched`, `vmap_get_aligned_vm_area`, `vmap_set_ptes`, `vmap_pages_pte_range`, `vmap_pages_pmd_range`, `vmap_pages_pud_range`, `vmap_pages_p4d_range`, `vmap_pages_range_noflush_walk`, `__vmap_pages_range_noflush`, `vmap`, `__vmalloc_node_range_noprof`, `arch_vmap_pte_range_map_size`, `num_contig_ptes`, and `arch_make_huge_pte` are going to be key players. My goal is to narrow down the actual symbols I need to investigate. `vmap` and `__vmalloc_node_range_noprof` are probably going to be the main entry points for the allocator. `vmap_pages_range_batched` and `vmap_get_aligned_vm_area` likely handle the bulk of the mapping process. `vmap_pages_range_noflush_walk` probably optimizes the mapping. I will ignore `vmap_set_ptes` because it is an `__always_inline` and `arch_vmap_pte_range_map_size`, and `num_contig_ptes` as they are `static inline` functions. I will need to look into `arch_make_huge_pte` as it is a function defined in `arch/arm64/mm/hugetlbpage.c`. |
| 6/2 | 2026/07/16 03:49 | tool | grepper |
0mArgs:{
"Expression": "arch_make_huge_pte"
}Results: {
"Output": "Documentation/mm/arch_pgtable_helpers.rst=203=HugeTLB Page Table Helpers\n--\nDocumentation/mm/arch_pgtable_helpers.rst-208-+---------------------------+--------------------------------------------------+\nDocumentation/mm/arch_pgtable_helpers.rst:209:| arch_make_huge_pte | Creates a HugeTLB |\nDocumentation/mm/arch_pgtable_helpers.rst-210-+---------------------------+--------------------------------------------------+\n--\narch/arm64/include/asm/hugetlb.h=22=static inline void arch_clear_hugetlb_flags(struct folio *folio)\n--\narch/arm64/include/asm/hugetlb.h-34-\narch/arm64/include/asm/hugetlb.h:35:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);\narch/arm64/include/asm/hugetlb.h:36:#define arch_make_huge_pte arch_make_huge_pte\narch/arm64/include/asm/hugetlb.h-37-#define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT\n--\narch/arm64/mm/hugetlbpage.c=78=static int find_num_contig(struct mm_struct *mm, unsigned long addr,\n--\narch/arm64/mm/hugetlbpage.c-97-/*\narch/arm64/mm/hugetlbpage.c:98: * num_contig_ptes(), set_huge_pte_at() and arch_make_huge_pte() can be\narch/arm64/mm/hugetlbpage.c-99- * used by non-hugetlbfs(vmalloc) mm code to set multiple huge mappings\n--\narch/arm64/mm/hugetlbpage.c=331=unsigned long hugetlb_mask_last_page(struct hstate *h)\n--\narch/arm64/mm/hugetlbpage.c-354-\narch/arm64/mm/hugetlbpage.c:355:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\narch/arm64/mm/hugetlbpage.c-356-{\n--\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h=38=static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,\n--\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h-47-#ifdef CONFIG_PPC_4K_PAGES\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h:48:static inline pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h-49-{\n--\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h-56-}\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h:57:#define arch_make_huge_pte arch_make_huge_pte\narch/powerpc/include/asm/nohash/32/hugetlb-8xx.h-58-#endif\n--\narch/powerpc/include/asm/nohash/hugetlb-e500.h=7=static inline int check_and_get_huge_psize(int shift)\n--\narch/powerpc/include/asm/nohash/hugetlb-e500.h-14-\narch/powerpc/include/asm/nohash/hugetlb-e500.h:15:static inline pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\narch/powerpc/include/asm/nohash/hugetlb-e500.h-16-{\n--\narch/powerpc/include/asm/nohash/hugetlb-e500.h-21-}\narch/powerpc/include/asm/nohash/hugetlb-e500.h:22:#define arch_make_huge_pte arch_make_huge_pte\narch/powerpc/include/asm/nohash/hugetlb-e500.h-23-\n--\narch/powerpc/mm/nohash/8xx.c=52=static int __ref __early_map_kernel_hugepage(unsigned long va, phys_addr_t pa,\n--\narch/powerpc/mm/nohash/8xx.c-90-\tset_huge_pte_at(\u0026init_mm, va, ptep,\narch/powerpc/mm/nohash/8xx.c:91:\t\t\tarch_make_huge_pte(pfn_pte(pa \u003e\u003e PAGE_SHIFT, prot), shift, 0),\narch/powerpc/mm/nohash/8xx.c-92-\t\t\t1UL \u003c\u003c shift);\n--\narch/riscv/include/asm/hugetlb.h=48=pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);\narch/riscv/include/asm/hugetlb.h-49-\narch/riscv/include/asm/hugetlb.h:50:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);\narch/riscv/include/asm/hugetlb.h:51:#define arch_make_huge_pte arch_make_huge_pte\narch/riscv/include/asm/hugetlb.h-52-\n--\narch/riscv/mm/hugetlbpage.c=172=static pte_t get_clear_contig_flush(struct mm_struct *mm,\n--\narch/riscv/mm/hugetlbpage.c-186-\narch/riscv/mm/hugetlbpage.c:187:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\narch/riscv/mm/hugetlbpage.c-188-{\n--\narch/sparc/include/asm/pgtable_64.h=374=static inline unsigned long pte_write(pte_t pte)\n--\narch/sparc/include/asm/pgtable_64.h-392-#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)\narch/sparc/include/asm/pgtable_64.h:393:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);\narch/sparc/include/asm/pgtable_64.h:394:#define arch_make_huge_pte arch_make_huge_pte\narch/sparc/include/asm/pgtable_64.h-395-static inline unsigned long __pte_default_huge_mask(void)\n--\narch/sparc/mm/hugetlbpage.c=81=static pte_t hugepage_shift_to_tte(pte_t entry, unsigned int shift)\n--\narch/sparc/mm/hugetlbpage.c-88-\narch/sparc/mm/hugetlbpage.c:89:pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)\narch/sparc/mm/hugetlbpage.c-90-{\n--\ninclude/linux/hugetlb.h=837=static inline void arch_clear_hugetlb_flags(struct folio *folio) { }\n--\ninclude/linux/hugetlb.h-840-\ninclude/linux/hugetlb.h:841:#ifndef arch_make_huge_pte\ninclude/linux/hugetlb.h:842:static inline pte_t arch_make_huge_pte(pte_t entry, unsigned int shift,\ninclude/linux/hugetlb.h-843-\t\t\t\t vm_flags_t flags)\n--\nmm/debug_vm_pgtable.c=885=static void __init hugetlb_basic_tests(struct pgtable_debug_args *args)\n--\nmm/debug_vm_pgtable.c-890-\tpte = pfn_pte(args-\u003efixed_pmd_pfn, args-\u003epage_prot);\nmm/debug_vm_pgtable.c:891:\tpte = arch_make_huge_pte(pte, PMD_SHIFT, VM_ACCESS_FLAGS);\nmm/debug_vm_pgtable.c-892-\n--\nmm/hugetlb.c=4804=static pte_t make_huge_pte(struct vm_area_struct *vma, struct folio *folio,\n--\nmm/hugetlb.c-4815-\tentry = pte_mkyoung(entry);\nmm/hugetlb.c:4816:\tentry = arch_make_huge_pte(entry, shift, vma-\u003evm_flags);\nmm/hugetlb.c-4817-\n--\nmm/hugetlb.c=6384=long hugetlb_change_protection(struct vm_area_struct *vma,\n--\nmm/hugetlb.c-6499-\t\t\tpte = huge_pte_modify(old_pte, newprot);\nmm/hugetlb.c:6500:\t\t\tpte = arch_make_huge_pte(pte, shift, vma-\u003evm_flags);\nmm/hugetlb.c-6501-\t\t\tif (uffd_wp)\n--\nmm/migrate.c=346=static bool remove_migration_pte(struct folio *folio,\n--\nmm/migrate.c-419-\nmm/migrate.c:420:\t\t\tpte = arch_make_huge_pte(pte, shift, vma-\u003evm_flags);\nmm/migrate.c-421-\t\t\tif (folio_test_anon(folio))\n--\nmm/vmalloc.c=101=static __always_inline unsigned long vmap_set_ptes(pte_t *pte,\n--\nmm/vmalloc.c-111-\nmm/vmalloc.c:112:\t\tentry = arch_make_huge_pte(entry, ilog2(size), 0);\nmm/vmalloc.c-113-\t\tset_huge_pte_at(\u0026init_mm, addr, pte, entry, size);\n"
} |
| 7/2 | 2026/07/16 03:49 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13482 output: 20 thoughts: 601 Thoughts: **My Analysis of Virtual Memory Mapping Functions and Configurations** Okay, so I'm diving into this virtual memory mapping code, and here's the breakdown of my current thought process. Initially, I'm zeroing in on a core set of functions: `vmap_pages_range_batched`, `vmap_get_aligned_vm_area`, `vmap_pages_range_noflush_walk`, `__vmap_pages_range_noflush`, `vmap`, `__vmalloc_node_range_noprof`, `vmap_pages_pte_range`, `vmap_pages_pmd_range`, `vmap_pages_pud_range`, and `vmap_pages_p4d_range`. I need to figure out how these pieces fit together. My first step is checking the visibility of `vmap_pages_range_batched` and `vmap_get_aligned_vm_area`. Aha, they're static within `mm/vmalloc.c`. Interesting. `vmap` is exported, as is `__vmalloc_node_range_noprof`. Similarly, `__vmap_pages_range_noflush` is also exported, while `vmap_pages_range_noflush_walk` is static. Given that these are the functions, I will include all functions listed in my thoughts: `vmap` `__vmalloc_node_range_noprof` `__vmap_pages_range_noflush` `vmap_pages_range_batched` `vmap_get_aligned_vm_area` `vmap_pages_range_noflush_walk` `vmap_pages_pte_range` `vmap_pages_pmd_range` `vmap_pages_pud_range` `vmap_pages_p4d_range` I realized I need to be *sure* to include `vmap_pages_range_batched` and `vmap_get_aligned_vm_area` because they are static but crucial, and also `arch_make_huge_pte` from `arch/arm64/mm/hugetlbpage.c`. Now, moving on to configuration considerations. I see `HAVE_ARCH_HUGE_VMALLOC`, `HAVE_ARCH_HUGE_VMAP`, and `HUGETLB_PAGE` are relevant. Wait, `HAVE_ARCH_HUGE_VMALLOC` and `HAVE_ARCH_HUGE_VMAP` are architecture-dependent, so I don't need to worry about user selection. However, `HUGETLB_PAGE` is a user-selectable config, so I need to check how it’s being used. Looking into the code, I see a `#ifdef CONFIG_HUGETLB_PAGE` inside `vmap_set_ptes`, which means the new code path within this function is only tested when the `HUGETLB_PAGE` config is enabled. Therefore, testing this code requires `HUGETLB_PAGE` to be enabled. I'll need to check `arch/arm64/Kconfig` to see how this is defined in that architecture. |
| 8/2 | 2026/07/16 03:49 | tool | grepper |
0mArgs:{
"Expression": "config HUGETLB_PAGE"
}Results: {
"Output": "arch/sh/mm/Kconfig=158=choice\n--\narch/sh/mm/Kconfig-163-\narch/sh/mm/Kconfig:164:config HUGETLB_PAGE_SIZE_64K\narch/sh/mm/Kconfig-165-\tbool \"64kB\"\n--\narch/sh/mm/Kconfig-167-\narch/sh/mm/Kconfig:168:config HUGETLB_PAGE_SIZE_256K\narch/sh/mm/Kconfig-169-\tbool \"256kB\"\n--\narch/sh/mm/Kconfig-171-\narch/sh/mm/Kconfig:172:config HUGETLB_PAGE_SIZE_1MB\narch/sh/mm/Kconfig-173-\tbool \"1MB\"\narch/sh/mm/Kconfig-174-\narch/sh/mm/Kconfig:175:config HUGETLB_PAGE_SIZE_4MB\narch/sh/mm/Kconfig-176-\tbool \"4MB\"\n--\narch/sh/mm/Kconfig-178-\narch/sh/mm/Kconfig:179:config HUGETLB_PAGE_SIZE_64MB\narch/sh/mm/Kconfig-180-\tbool \"64MB\"\n--\nfs/Kconfig=262=if HUGETLBFS\nfs/Kconfig:263:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON\nfs/Kconfig-264-\tbool \"HugeTLB Vmemmap Optimization (HVO) defaults to on\"\n--\nfs/Kconfig=271=endif # HUGETLBFS\nfs/Kconfig-272-\nfs/Kconfig:273:config HUGETLB_PAGE\nfs/Kconfig-274-\tdef_bool HUGETLBFS\n--\nfs/Kconfig-276-\nfs/Kconfig:277:config HUGETLB_PAGE_OPTIMIZE_VMEMMAP\nfs/Kconfig-278-\tdef_bool HUGETLB_PAGE\n--\nmm/Kconfig=706=config ARCH_ENABLE_THP_MIGRATION\n--\nmm/Kconfig-708-\nmm/Kconfig:709:config HUGETLB_PAGE_SIZE_VARIABLE\nmm/Kconfig-710-\tdef_bool n\n"
} |
| 9/2 | 2026/07/16 03:49 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15404 output: 19 thoughts: 33 Thoughts: Okay, here's my interpretation of that. **Analyzing the HugeTLB Page Definition** Alright, let's break this down. From what I'm seeing, `HUGETLB_PAGE` is essentially defined as the same thing as `def_bool HUGETLBFS`. This means the `HUGETLBFS` configuration option is the key to enabling the `HUGETLB_PAGE` functionality. So, if I want to work with huge pages, I need to ensure that `HUGETLBFS` is enabled within the system configuration. That seems straightforward enough. It tells me where to look to ensure it's available. |
| 10/2 | 2026/07/16 03:49 | tool | grepper |
0mArgs:{
"Expression": "config HUGETLBFS"
}Results: {
"Output": "fs/Kconfig=247=config ARCH_SUPPORTS_HUGETLBFS\n--\nfs/Kconfig-249-\nfs/Kconfig:250:menuconfig HUGETLBFS\nfs/Kconfig-251-\tbool \"HugeTLB file system support\"\n"
} |
| 11/2 | 2026/07/16 03:49 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15671 output: 213 thoughts: 490 Thoughts: **Analyzing the Contiguous PTE Mapping Patch** Okay, so I've confirmed that enabling `HUGETLBFS` is the relevant config for this patch. I also see that `CONFIG_HAVE_ARCH_HUGE_VMALLOC` and `CONFIG_HAVE_ARCH_HUGE_VMAP` are selected by arm64, but `HUGETLBFS` is the key one. I've taken a look at the various symbols touched by this patch: `vmap`, and the functions dealing with page table manipulation for `vmap` - `__vmalloc_node_range_noprof`, `__vmap_pages_range_noflush`, `vmap_pages_range_batched`, `vmap_get_aligned_vm_area`, `vmap_pages_range_noflush_walk`, `vmap_pages_pte_range`, `vmap_pages_pmd_range`, `vmap_pages_pud_range`, `vmap_pages_p4d_range` and finally, critically, `arch_make_huge_pte`. I've checked and `arch_make_huge_pte` *is* defined in `arch/arm64/mm/hugetlbpage.c`. Other architectures, like powerpc, riscv, and sparc also define it but the patch specifically touches the arm64 implementation. The patch modifies `arch/arm64/include/asm/vmalloc.h`, `arch/arm64/mm/hugetlbpage.c`, and `mm/vmalloc.c`. The changes in `mm/vmalloc.c` are architecture-independent but rely on `arch_vmap_pte_range_map_size` and `arch_make_huge_pte` defined by the architecture. So the core of this seems to be the addition of contiguous PTE mappings for vmalloc on arm64. Therefore, this patch is a functional change to the core memory management subsystem and the arm64 architecture. It introduces contiguous PTE mappings for vmalloc on arm64 and updates `vmap` to support batched mapping for contiguous pages. This touches core memory management logic and architecture-specific page table manipulation. Given these changes, this is absolutely worth fuzzing to ensure correctness and stability. I should use the `set-results` tool and mark this as an important fuzzing target. |
| 12/2 | 2026/07/16 03:49 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"HUGETLBFS"
],
"FocusSymbols": [
"vmap",
"__vmalloc_node_range_noprof",
"__vmap_pages_range_noflush",
"vmap_pages_range_batched",
"vmap_get_aligned_vm_area",
"vmap_pages_range_noflush_walk",
"vmap_pages_pte_range",
"vmap_pages_pmd_range",
"vmap_pages_pud_range",
"vmap_pages_p4d_range",
"arch_make_huge_pte"
],
"Reasoning": "The patch introduces contiguous PTE mappings for vmalloc on arm64, and updates vmap to support batched mapping for contiguous pages. This modifies core memory management logic and architecture-specific page table manipulation, which are reachable and functional changes.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"HUGETLBFS"
],
"FocusSymbols": [
"vmap",
"__vmalloc_node_range_noprof",
"__vmap_pages_range_noflush",
"vmap_pages_range_batched",
"vmap_get_aligned_vm_area",
"vmap_pages_range_noflush_walk",
"vmap_pages_pte_range",
"vmap_pages_pmd_range",
"vmap_pages_pud_range",
"vmap_pages_p4d_range",
"arch_make_huge_pte"
],
"Reasoning": "The patch introduces contiguous PTE mappings for vmalloc on arm64, and updates vmap to support batched mapping for contiguous pages. This modifies core memory management logic and architecture-specific page table manipulation, which are reachable and functional changes.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|