| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/20 16:12 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"ZONE_DEVICE"
],
"FocusSymbols": [
"memmap_init_zone_device",
"memmap_init_compound"
],
"Reasoning": "The patch introduces a functional optimization for initializing `struct page` structures for ZONE_DEVICE memory using non-temporal stores (`memcpy_nontemporal`). This modifies core memory management initialization paths and x86 string routines. It is reachable when probing devices that use ZONE_DEVICE memory (e.g., DAX, PMEM, virtio-fs DAX).",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/20 16:12 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 595d986f8f07b6404f6e6ede9e30da179b4c4017\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 20 16:12:27 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h\nindex 4635616863f53d..bc6a9f34b346af 100644\n--- a/arch/x86/include/asm/string_64.h\n+++ b/arch/x86/include/asm/string_64.h\n@@ -82,7 +82,35 @@ int strcmp(const char *cs, const char *ct);\n #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\n #define __HAVE_ARCH_MEMCPY_FLUSHCACHE 1\n void __memcpy_flushcache(void *dst, const void *src, size_t cnt);\n-static __always_inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)\n+\n+static __always_inline void movnti_8(void *dst, const void *src)\n+{\n+\tasm volatile(\"movntiq %1, %0\"\n+\t\t : \"=m\"(*(u64 *)dst)\n+\t\t : \"r\"(*(const u64 *)src)\n+\t\t : \"memory\");\n+}\n+\n+static __always_inline void movnti_16(void *dst, const void *src)\n+{\n+\tmovnti_8(dst, src);\n+\tmovnti_8(dst + 8, src + 8);\n+}\n+\n+static __always_inline void movnti_32(void *dst, const void *src)\n+{\n+\tmovnti_16(dst, src);\n+\tmovnti_16(dst + 16, src + 16);\n+}\n+\n+static __always_inline void movnti_64(void *dst, const void *src)\n+{\n+\tmovnti_32(dst, src);\n+\tmovnti_32(dst + 32, src + 32);\n+}\n+\n+static __always_inline void memcpy_flushcache(void *dst, const void *src,\n+\t\t\t\t\t size_t cnt)\n {\n \tif (__builtin_constant_p(cnt)) {\n \t\tswitch (cnt) {\n@@ -96,10 +124,48 @@ static __always_inline void memcpy_flushcache(void *dst, const void *src, size_t\n \t\t\t\tasm (\"movntiq %1, %0\" : \"=m\"(*(u64 *)dst) : \"r\"(*(u64 *)src));\n \t\t\t\tasm (\"movntiq %1, %0\" : \"=m\"(*(u64 *)(dst + 8)) : \"r\"(*(u64 *)(src + 8)));\n \t\t\t\treturn;\n+\t\t\t/*\n+\t\t\t * The relevant fixed-size copies here are the\n+\t\t\t * x86_64 struct page sizes: 64, 80, and 96 bytes.\n+\t\t\t * Keep 32-byte and 48-byte copies inline as well\n+\t\t\t * instead of sending those nearby fixed-size\n+\t\t\t * cases back to __memcpy_flushcache().\n+\t\t\t */\n+\t\t\tcase 32:\n+\t\t\t\tmovnti_32(dst, src);\n+\t\t\t\treturn;\n+\t\t\tcase 48:\n+\t\t\t\tmovnti_32(dst, src);\n+\t\t\t\tmovnti_16(dst + 32, src + 32);\n+\t\t\t\treturn;\n+\t\t\tcase 64:\n+\t\t\t\tmovnti_64(dst, src);\n+\t\t\t\treturn;\n+\t\t\tcase 80:\n+\t\t\t\tmovnti_64(dst, src);\n+\t\t\t\tmovnti_16(dst + 64, src + 64);\n+\t\t\t\treturn;\n+\t\t\tcase 96:\n+\t\t\t\tmovnti_64(dst, src);\n+\t\t\t\tmovnti_32(dst + 64, src + 64);\n+\t\t\t\treturn;\n \t\t}\n \t}\n+\n \t__memcpy_flushcache(dst, src, cnt);\n }\n+\n+#define memcpy_nontemporal memcpy_nontemporal\n+/*\n+ * Reuse the existing x86 flushcache backend as the non-temporal copy\n+ * primitive.\n+ */\n+static __always_inline void memcpy_nontemporal(void *dst, const void *src,\n+\t\tsize_t cnt)\n+{\n+\tmemcpy_flushcache(dst, src, cnt);\n+}\n+\n #endif\n \n #endif /* __KERNEL__ */\ndiff --git a/include/linux/mm.h b/include/linux/mm.h\nindex 485df9c2dbddb3..43343bfce4936e 100644\n--- a/include/linux/mm.h\n+++ b/include/linux/mm.h\n@@ -2541,11 +2541,22 @@ static inline void set_page_section(struct page *page, unsigned long section)\n \tpage-\u003eflags.f |= (section \u0026 SECTIONS_MASK) \u003c\u003c SECTIONS_PGSHIFT;\n }\n \n+static inline void set_page_section_from_pfn(struct page *page,\n+\t\tunsigned long pfn)\n+{\n+\tset_page_section(page, pfn_to_section_nr(pfn));\n+}\n+\n static inline unsigned long memdesc_section(memdesc_flags_t mdf)\n {\n \treturn (mdf.f \u003e\u003e SECTIONS_PGSHIFT) \u0026 SECTIONS_MASK;\n }\n #else /* !SECTION_IN_PAGE_FLAGS */\n+static inline void set_page_section_from_pfn(struct page *page,\n+\t\tunsigned long pfn)\n+{\n+}\n+\n static inline unsigned long memdesc_section(memdesc_flags_t mdf)\n {\n \treturn 0;\n@@ -2768,9 +2779,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,\n {\n \tset_page_zone(page, zone);\n \tset_page_node(page, node);\n-#ifdef SECTION_IN_PAGE_FLAGS\n-\tset_page_section(page, pfn_to_section_nr(pfn));\n-#endif\n+\tset_page_section_from_pfn(page, pfn);\n }\n \n /**\ndiff --git a/include/linux/string.h b/include/linux/string.h\nindex 5702daca4326b7..9815c08867d729 100644\n--- a/include/linux/string.h\n+++ b/include/linux/string.h\n@@ -278,6 +278,18 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)\n }\n #endif\n \n+#ifndef memcpy_nontemporal\n+/*\n+ * memcpy_nontemporal() requests a non-temporal copy when the\n+ * architecture has a suitable backend. Architectures without a\n+ * specialized backend fall back to memcpy(). Keep this as a macro alias\n+ * so the compiler can still see the original memcpy() call site and\n+ * preserve the usual FORTIFY coverage when object sizes remain visible\n+ * there.\n+ */\n+#define memcpy_nontemporal memcpy\n+#endif\n+\n void *memchr_inv(const void *s, int c, size_t n);\n char *strreplace(char *str, char old, char new);\n \ndiff --git a/mm/mm_init.c b/mm/mm_init.c\nindex 0f64909e8d20e2..ae42a1311e1d18 100644\n--- a/mm/mm_init.c\n+++ b/mm/mm_init.c\n@@ -1005,11 +1005,37 @@ static void __init memmap_init(void)\n }\n \n #ifdef CONFIG_ZONE_DEVICE\n-static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,\n+/*\n+ * Return true when memmap_init_zone_device() must initialize the page\n+ * refcount to 0. MEMORY_DEVICE_GENERIC pages regain a refcount of 1 in\n+ * the free path, while the remaining ZONE_DEVICE types start from 0 here\n+ * and raise the count again when the allocator or driver hands the page\n+ * out.\n+ */\n+static inline bool pagemap_requires_refcount_reset(const struct dev_pagemap *pgmap)\n+{\n+\t/*\n+\t * MEMORY_DEVICE_GENERIC pages regain a refcount of 1 in the free\n+\t * path. The remaining ZONE_DEVICE types start from 0 here and raise\n+\t * the count again when the allocator or driver hands the page out.\n+\t */\n+\tswitch (pgmap-\u003etype) {\n+\tcase MEMORY_DEVICE_FS_DAX:\n+\tcase MEMORY_DEVICE_PRIVATE:\n+\tcase MEMORY_DEVICE_COHERENT:\n+\tcase MEMORY_DEVICE_PCI_P2PDMA:\n+\t\treturn true;\n+\tcase MEMORY_DEVICE_GENERIC:\n+\t\treturn false;\n+\t}\n+\n+\treturn false;\n+}\n+\n+static void __ref __zone_device_page_init(struct page *page, unsigned long pfn,\n \t\t\t\t\t unsigned long zone_idx, int nid,\n \t\t\t\t\t struct dev_pagemap *pgmap)\n {\n-\n \t__init_single_page(page, pfn, zone_idx, nid);\n \n \t/*\n@@ -1028,27 +1054,54 @@ static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,\n \t */\n \tpage_folio(page)-\u003epgmap = pgmap;\n \tpage-\u003ezone_device_data = NULL;\n+}\n \n-\t/*\n-\t * ZONE_DEVICE pages other than MEMORY_TYPE_GENERIC are released\n-\t * directly to the driver page allocator which will set the page count\n-\t * to 1 when allocating the page.\n-\t *\n-\t * MEMORY_TYPE_GENERIC and MEMORY_TYPE_FS_DAX pages automatically have\n-\t * their refcount reset to one whenever they are freed (ie. after\n-\t * their refcount drops to 0).\n-\t */\n-\tswitch (pgmap-\u003etype) {\n-\tcase MEMORY_DEVICE_FS_DAX:\n-\tcase MEMORY_DEVICE_PRIVATE:\n-\tcase MEMORY_DEVICE_COHERENT:\n-\tcase MEMORY_DEVICE_PCI_P2PDMA:\n+static void __ref zone_device_page_init_slow(struct page *page,\n+\t\tunsigned long pfn, unsigned long zone_idx, int nid,\n+\t\tstruct dev_pagemap *pgmap)\n+{\n+\t__zone_device_page_init(page, pfn, zone_idx, nid, pgmap);\n+\tif (pagemap_requires_refcount_reset(pgmap))\n \t\tset_page_count(page, 0);\n-\t\tbreak;\n+}\n \n-\tcase MEMORY_DEVICE_GENERIC:\n-\t\tbreak;\n-\t}\n+static inline void zone_device_tail_page_init(struct page *page,\n+\t\tunsigned long pfn, unsigned long zone_idx, int nid,\n+\t\tstruct dev_pagemap *pgmap, const struct page *head,\n+\t\tunsigned int order)\n+{\n+\tzone_device_page_init_slow(page, pfn, zone_idx, nid, pgmap);\n+\tprep_compound_tail(page, head, order);\n+\tset_page_count(page, 0);\n+}\n+\n+/*\n+ * 'template' is a reusable page prototype rather than a strictly immutable\n+ * object. Most ZONE_DEVICE fields stay constant across the pages covered by\n+ * the current template, but section bits and page-\u003evirtual may still depend\n+ * on the PFN. Refresh those PFN-dependent fields in the template before\n+ * copying it into @page.\n+ */\n+static inline void zone_device_page_update_template(struct page *template,\n+\t\tunsigned long pfn)\n+{\n+\tset_page_section_from_pfn(template, pfn);\n+#ifdef WANT_PAGE_VIRTUAL\n+\tif (!is_highmem_idx(ZONE_DEVICE))\n+\t\tset_page_address(template, __va(pfn \u003c\u003c PAGE_SHIFT));\n+#endif\n+}\n+\n+static void zone_device_page_init_from_template(struct page *page,\n+\t\tunsigned long pfn, struct page *template)\n+{\n+\t/*\n+\t * 'template' carries the invariant portion of a ZONE_DEVICE struct\n+\t * page. Update the PFN-dependent fields in place before copying it\n+\t * to the destination page.\n+\t */\n+\tzone_device_page_update_template(template, pfn);\n+\tmemcpy_nontemporal(page, template, sizeof(*page));\n }\n \n /*\n@@ -1083,6 +1136,7 @@ static void __ref memmap_init_compound(struct page *head,\n {\n \tunsigned long pfn, end_pfn = head_pfn + nr_pages;\n \tunsigned int order = pgmap-\u003evmemmap_shift;\n+\tstruct page template;\n \n \t/*\n \t * We have to initialize the pages, including setting up page links.\n@@ -1091,12 +1145,26 @@ static void __ref memmap_init_compound(struct page *head,\n \t * the pages in the same go.\n \t */\n \t__SetPageHead(head);\n+\n \tfor (pfn = head_pfn + 1; pfn \u003c end_pfn; pfn++) {\n \t\tstruct page *page = pfn_to_page(pfn);\n \n-\t\t__init_zone_device_page(page, pfn, zone_idx, nid, pgmap);\n-\t\tprep_compound_tail(page, head, order);\n-\t\tset_page_count(page, 0);\n+\t\tif (pfn == head_pfn + 1) {\n+\t\t\t/*\n+\t\t\t * All tails of the same compound page share the\n+\t\t\t * state established by prep_compound_tail(). Reuse\n+\t\t\t * one tail template for the whole range and\n+\t\t\t * refresh only the PFN-dependent fields in that\n+\t\t\t * template before each copy.\n+\t\t\t */\n+\t\t\tzone_device_tail_page_init(page, pfn, zone_idx, nid,\n+\t\t\t\t\t\t pgmap, head, order);\n+\t\t\t/* init template page */\n+\t\t\tmemcpy(\u0026template, page, sizeof(*page));\n+\t\t} else {\n+\t\t\tzone_device_page_init_from_template(page, pfn,\n+\t\t\t\t\t\t\t \u0026template);\n+\t\t}\n \t}\n \tprep_compound_head(head, order);\n }\n@@ -1113,6 +1181,7 @@ void __ref memmap_init_zone_device(struct zone *zone,\n \tunsigned long zone_idx = zone_idx(zone);\n \tunsigned long start = jiffies;\n \tint nid = pgdat-\u003enode_id;\n+\tstruct page template;\n \n \tif (WARN_ON_ONCE(!pgmap || zone_idx != ZONE_DEVICE))\n \t\treturn;\n@@ -1130,7 +1199,21 @@ void __ref memmap_init_zone_device(struct zone *zone,\n \tfor (pfn = start_pfn; pfn \u003c end_pfn; pfn += pfns_per_compound) {\n \t\tstruct page *page = pfn_to_page(pfn);\n \n-\t\t__init_zone_device_page(page, pfn, zone_idx, nid, pgmap);\n+\t\tif (pfn == start_pfn) {\n+\t\t\t/*\n+\t\t\t * Seed the reusable head-page template from the\n+\t\t\t * first real struct page, because the existing\n+\t\t\t * page-init and pageblock helpers expect a real\n+\t\t\t * memmap entry rather than a stack object.\n+\t\t\t */\n+\t\t\tzone_device_page_init_slow(page, pfn, zone_idx,\n+\t\t\t\t\t\t nid, pgmap);\n+\t\t\t/* init template page */\n+\t\t\tmemcpy(\u0026template, page, sizeof(*page));\n+\t\t} else {\n+\t\t\tzone_device_page_init_from_template(page, pfn,\n+\t\t\t\t\t\t\t \u0026template);\n+\t\t}\n \n \t\tif (IS_ALIGNED(pfn, PAGES_PER_SECTION))\n \t\t\tcond_resched();\n"
} |
| 2/1 | 2026/07/20 16:12 | agent | patch-evaluator |
1mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"ZONE_DEVICE"
],
"FocusSymbols": [
"memmap_init_zone_device",
"memmap_init_compound"
],
"Reasoning": "The patch introduces a functional optimization for initializing `struct page` structures for ZONE_DEVICE memory using non-temporal stores (`memcpy_nontemporal`). This modifies core memory management initialization paths and x86 string routines. It is reachable when probing devices that use ZONE_DEVICE memory (e.g., DAX, PMEM, virtio-fs DAX).",
"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 595d986f8f07b6404f6e6ede9e30da179b4c4017
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 20 16:12:27 2026 +0000
syz-cluster: applied patch under review
diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h
index 4635616863f53d..bc6a9f34b346af 100644
--- a/arch/x86/include/asm/string_64.h
+++ b/arch/x86/include/asm/string_64.h
@@ -82,7 +82,35 @@ int strcmp(const char *cs, const char *ct);
#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
#define __HAVE_ARCH_MEMCPY_FLUSHCACHE 1
void __memcpy_flushcache(void *dst, const void *src, size_t cnt);
-static __always_inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
+
+static __always_inline void movnti_8(void *dst, const void *src)
+{
+ asm volatile("movntiq %1, %0"
+ : "=m"(*(u64 *)dst)
+ : "r"(*(const u64 *)src)
+ : "memory");
+}
+
+static __always_inline void movnti_16(void *dst, const void *src)
+{
+ movnti_8(dst, src);
+ movnti_8(dst + 8, src + 8);
+}
+
+static __always_inline void movnti_32(void *dst, const void *src)
+{
+ movnti_16(dst, src);
+ movnti_16(dst + 16, src + 16);
+}
+
+static __always_inline void movnti_64(void *dst, const void *src)
+{
+ movnti_32(dst, src);
+ movnti_32(dst + 32, src + 32);
+}
+
+static __always_inline void memcpy_flushcache(void *dst, const void *src,
+ size_t cnt)
{
if (__builtin_constant_p(cnt)) {
switch (cnt) {
@@ -96,10 +124,48 @@ static __always_inline void memcpy_flushcache(void *dst, const void *src, size_t
asm ("movntiq %1, %0" : "=m"(*(u64 *)dst) : "r"(*(u64 *)src));
asm ("movntiq %1, %0" : "=m"(*(u64 *)(dst + 8)) : "r"(*(u64 *)(src + 8)));
return;
+ /*
+ * The relevant fixed-size copies here are the
+ * x86_64 struct page sizes: 64, 80, and 96 bytes.
+ * Keep 32-byte and 48-byte copies inline as well
+ * instead of sending those nearby fixed-size
+ * cases back to __memcpy_flushcache().
+ */
+ case 32:
+ movnti_32(dst, src);
+ return;
+ case 48:
+ movnti_32(dst, src);
+ movnti_16(dst + 32, src + 32);
+ return;
+ case 64:
+ movnti_64(dst, src);
+ return;
+ case 80:
+ movnti_64(dst, src);
+ movnti_16(dst + 64, src + 64);
+ return;
+ case 96:
+ movnti_64(dst, src);
+ movnti_32(dst + 64, src + 64);
+ return;
}
}
+
__memcpy_flushcache(dst, src, cnt);
}
+
+#define memcpy_nontemporal memcpy_nontemporal
+/*
+ * Reuse the existing x86 flushcache backend as the non-temporal copy
+ * primitive.
+ */
+static __always_inline void memcpy_nontemporal(void *dst, const void *src,
+ size_t cnt)
+{
+ memcpy_flushcache(dst, src, cnt);
+}
+
#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 485df9c2dbddb3..43343bfce4936e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2541,11 +2541,22 @@ static inline void set_page_section(struct page *page, unsigned long section)
page->flags.f |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
}
+static inline void set_page_section_from_pfn(struct page *page,
+ unsigned long pfn)
+{
+ set_page_section(page, pfn_to_section_nr(pfn));
+}
+
static inline unsigned long memdesc_section(memdesc_flags_t mdf)
{
return (mdf.f >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}
#else /* !SECTION_IN_PAGE_FLAGS */
+static inline void set_page_section_from_pfn(struct page *page,
+ unsigned long pfn)
+{
+}
+
static inline unsigned long memdesc_section(memdesc_flags_t mdf)
{
return 0;
@@ -2768,9 +2779,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
{
set_page_zone(page, zone);
set_page_node(page, node);
-#ifdef SECTION_IN_PAGE_FLAGS
- set_page_section(page, pfn_to_section_nr(pfn));
-#endif
+ set_page_section_from_pfn(page, pfn);
}
/**
diff --git a/include/linux/string.h b/include/linux/string.h
index 5702daca4326b7..9815c08867d729 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -278,6 +278,18 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
}
#endif
+#ifndef memcpy_nontemporal
+/*
+ * memcpy_nontemporal() requests a non-temporal copy when the
+ * architecture has a suitable backend. Architectures without a
+ * specialized backend fall back to memcpy(). Keep this as a macro alias
+ * so the compiler can still see the original memcpy() call site and
+ * preserve the usual FORTIFY coverage when object sizes remain visible
+ * there.
+ */
+#define memcpy_nontemporal memcpy
+#endif
+
void *memchr_inv(const void *s, int c, size_t n);
char *strreplace(char *str, char old, char new);
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 0f64909e8d20e2..ae42a1311e1d18 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -1005,11 +1005,37 @@ static void __init memmap_init(void)
}
#ifdef CONFIG_ZONE_DEVICE
-static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,
+/*
+ * Return true when memmap_init_zone_device() must initialize the page
+ * refcount to 0. MEMORY_DEVICE_GENERIC pages regain a refcount of 1 in
+ * the free path, while the remaining ZONE_DEVICE types start from 0 here
+ * and raise the count again when the allocator or driver hands the page
+ * out.
+ */
+static inline bool pagemap_requires_refcount_reset(const struct dev_pagemap *pgmap)
+{
+ /*
+ * MEMORY_DEVICE_GENERIC pages regain a refcount of 1 in the free
+ * path. The remaining ZONE_DEVICE types start from 0 here and raise
+ * the count again when the allocator or driver hands the page out.
+ */
+ switch (pgmap->type) {
+ case MEMORY_DEVICE_FS_DAX:
+ case MEMORY_DEVICE_PRIVATE:
+ case MEMORY_DEVICE_COHERENT:
+ case MEMORY_DEVICE_PCI_P2PDMA:
+ return true;
+ case MEMORY_DEVICE_GENERIC:
+ return false;
+ }
+
+ return false;
+}
+
+static void __ref __zone_device_page_init(struct page *page, unsigned long pfn,
unsigned long zone_idx, int nid,
struct dev_pagemap *pgmap)
{
-
__init_single_page(page, pfn, zone_idx, nid);
/*
@@ -1028,27 +1054,54 @@ static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,
*/
page_folio(page)->pgmap = pgmap;
page->zone_device_data = NULL;
+}
- /*
- * ZONE_DEVICE pages other than MEMORY_TYPE_GENERIC are released
- * directly to the driver page allocator which will set the page count
- * to 1 when allocating the page.
- *
- * MEMORY_TYPE_GENERIC and MEMORY_TYPE_FS_DAX pages automatically have
- * their refcount reset to one whenever they are freed (ie. after
- * their refcount drops to 0).
- */
- switch (pgmap->type) {
- case MEMORY_DEVICE_FS_DAX:
- case MEMORY_DEVICE_PRIVATE:
- case MEMORY_DEVICE_COHERENT:
- case MEMORY_DEVICE_PCI_P2PDMA:
+static void __ref zone_device_page_init_slow(struct page *page,
+ unsigned long pfn, unsigned long zone_idx, int nid,
+ struct dev_pagemap *pgmap)
+{
+ __zone_device_page_init(page, pfn, zone_idx, nid, pgmap);
+ if (pagemap_requires_refcount_reset(pgmap))
set_page_count(page, 0);
- break;
+}
- case MEMORY_DEVICE_GENERIC:
- break;
- }
+static inline void zone_device_tail_page_init(struct page *page,
+ unsigned long pfn, unsigned long zone_idx, int nid,
+ struct dev_pagemap *pgmap, const struct page *head,
+ unsigned int order)
+{
+ zone_device_page_init_slow(page, pfn, zone_idx, nid, pgmap);
+ prep_compound_tail(page, head, order);
+ set_page_count(page, 0);
+}
+
+/*
+ * 'template' is a reusable page prototype rather than a strictly immutable
+ * object. Most ZONE_DEVICE fields stay constant across the pages covered by
+ * the current template, but section bits and page->virtual may still depend
+ * on the PFN. Refresh those PFN-dependent fields in the template before
+ * copying it into @page.
+ */
+static inline void zone_device_page_update_template(struct page *template,
+ unsigned long pfn)
+{
+ set_page_section_from_pfn(template, pfn);
+#ifdef WANT_PAGE_VIRTUAL
+ if (!is_highmem_idx(ZONE_DEVICE))
+ set_page_address(template, __va(pfn << PAGE_SHIFT));
+#endif
+}
+
+static void zone_device_page_init_from_template(struct page *page,
+ unsigned long pfn, struct page *template)
+{
+ /*
+ * 'template' carries the invariant portion of a ZONE_DEVICE struct
+ * page. Update the PFN-dependent fields in place before copying it
+ * to the destination page.
+ */
+ zone_device_page_update_template(template, pfn);
+ memcpy_nontemporal(page, template, sizeof(*page));
}
/*
@@ -1083,6 +1136,7 @@ static void __ref memmap_init_compound(struct page *head,
{
unsigned long pfn, end_pfn = head_pfn + nr_pages;
unsigned int order = pgmap->vmemmap_shift;
+ struct page template;
/*
* We have to initialize the pages, including setting up page links.
@@ -1091,12 +1145,26 @@ static void __ref memmap_init_compound(struct page *head,
* the pages in the same go.
*/
__SetPageHead(head);
+
for (pfn = head_pfn + 1; pfn < end_pfn; pfn++) {
struct page *page = pfn_to_page(pfn);
- __init_zone_device_page(page, pfn, zone_idx, nid, pgmap);
- prep_compound_tail(page, head, order);
- set_page_count(page, 0);
+ if (pfn == head_pfn + 1) {
+ /*
+ * All tails of the same compound page share the
+ * state established by prep_compound_tail(). Reuse
+ * one tail template for the whole range and
+ * refresh only the PFN-dependent fields in that
+ * template before each copy.
+ */
+ zone_device_tail_page_init(page, pfn, zone_idx, nid,
+ pgmap, head, order);
+ /* init template page */
+ memcpy(&template, page, sizeof(*page));
+ } else {
+ zone_device_page_init_from_template(page, pfn,
+ &template);
+ }
}
prep_compound_head(head, order);
}
@@ -1113,6 +1181,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
unsigned long zone_idx = zone_idx(zone);
unsigned long start = jiffies;
int nid = pgdat->node_id;
+ struct page template;
if (WARN_ON_ONCE(!pgmap || zone_idx != ZONE_DEVICE))
return;
@@ -1130,7 +1199,21 @@ void __ref memmap_init_zone_device(struct zone *zone,
for (pfn = start_pfn; pfn < end_pfn; pfn += pfns_per_compound) {
struct page *page = pfn_to_page(pfn);
- __init_zone_device_page(page, pfn, zone_idx, nid, pgmap);
+ if (pfn == start_pfn) {
+ /*
+ * Seed the reusable head-page template from the
+ * first real struct page, because the existing
+ * page-init and pageblock helpers expect a real
+ * memmap entry rather than a stack object.
+ */
+ zone_device_page_init_slow(page, pfn, zone_idx,
+ nid, pgmap);
+ /* init template page */
+ memcpy(&template, page, sizeof(*page));
+ } else {
+ zone_device_page_init_from_template(page, pfn,
+ &template);
+ }
if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
cond_resched();
|
| 3/2 | 2026/07/20 16:12 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5746 output: 22 thoughts: 407 Thoughts: **Analyzing a Patch for ZONE_DEVICE Memory Initialization** Okay, so I'm looking at this patch that touches several key files: `arch/x86/include/asm/string_64.h`, `include/linux/mm.h`, `include/linux/string.h`, and `mm/mm_init.c`. The core of it seems to be introducing a `memcpy_nontemporal` function, and then using it within `memmap_init_zone_device` and `memmap_init_compound`. From a quick glance, it looks like this is all about initializing `struct page` structures specifically for ZONE_DEVICE memory. It also includes adding `movnti_8`, `movnti_16`, `movnti_32`, and `movnti_64` to `x86 string_64.h`. The first question that pops into my head is, can we actually *hit* this code path in a virtualized environment? `memmap_init_zone_device` is used for ZONE_DEVICE memory, which is commonly associated with DAX, PMEM, and similar technologies. Sure, we can emulate NVDIMM or PMEM devices within QEMU, or use `memmap=...!something` to force the creation of ZONE_DEVICE memory. But the critical question is, can this be triggered by syzkaller? Syzkaller can work with `/dev/dax` if properly configured, but does it directly call `memmap_init_zone_device` on its own? Maybe it is called during memory hotplug. No, wait, `memmap_init_zone_device` is called when a device is probed. So when a pmem or dax device is initialized. Syzkaller usually doesn't hotplug pmem devices dynamically unless it's through some specific drivers (like ndctl/nvdimm). Hmmm, interesting. So, is it even *worth* fuzzing this? Essentially, this patch is optimizing `struct page` initialization for ZONE_DEVICE by leveraging non-temporal stores (`movnti`). It's definitely a functional change in core MM and x86 string routines. This could be useful for speeding up the initialization phase if these non-temporal stores are faster. Okay, I'll need to go deeper and search for further usages of `memmap_init_zone_device` to see where else it's called and how it's used. Let's see... |
| 4/2 | 2026/07/20 16:12 | tool | grepper |
0mArgs:{
"Expression": "memmap_init_zone_device"
}Results: {
"Output": "include/linux/mmzone.h=1311=static inline bool zone_device_pages_have_same_pgmap(const struct page *a,\n--\ninclude/linux/mmzone.h-1320-\ninclude/linux/mmzone.h:1321:extern void memmap_init_zone_device(struct zone *, unsigned long,\ninclude/linux/mmzone.h-1322-\t\t\t\t unsigned long, struct dev_pagemap *);\n--\nmm/memremap.c=144=static int pagemap_range(struct dev_pagemap *pgmap, struct mhp_params *params,\n--\nmm/memremap.c-241-\t */\nmm/memremap.c:242:\tmemmap_init_zone_device(\u0026NODE_DATA(nid)-\u003enode_zones[ZONE_DEVICE],\nmm/memremap.c-243-\t\t\t\tPHYS_PFN(range-\u003estart),\n--\nmm/mm_init.c=968=static void __init memmap_init(void)\n--\nmm/mm_init.c-1008-/*\nmm/mm_init.c:1009: * Return true when memmap_init_zone_device() must initialize the page\nmm/mm_init.c-1010- * refcount to 0. MEMORY_DEVICE_GENERIC pages regain a refcount of 1 in\n--\nmm/mm_init.c=1131=static void __ref memmap_init_compound(struct page *head,\n--\nmm/mm_init.c-1171-\nmm/mm_init.c:1172:void __ref memmap_init_zone_device(struct zone *zone,\nmm/mm_init.c-1173-\t\t\t\t unsigned long start_pfn,\n"
} |
| 5/2 | 2026/07/20 16:12 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7160 output: 19 thoughts: 46 Thoughts: Here's my take on the thought process, summarized as you requested: **Tracing the Origins of memmap_init_zone_device** Okay, so `memmap_init_zone_device` is the target, and it looks like it's being invoked from `pagemap_range` within `mm/memremap.c`. That's a good starting point. Now, to understand the context and how we got *here*, I need to trace back from `pagemap_range`. I want to identify the callers of `pagemap_range`. Knowing the calling context of `pagemap_range` will give me critical insights into the purpose and implications of `memmap_init_zone_device`. Let's see what that reveals. I'll need to use my usual tools to dig up all the call sites of `pagemap_range`. |
| 6/2 | 2026/07/20 16:12 | tool | grepper |
0mArgs:{
"Expression": "pagemap_range"
}Results: {
"Output": "mm/memremap.c=137=static void dev_pagemap_percpu_release(struct percpu_ref *ref)\n--\nmm/memremap.c-143-\nmm/memremap.c:144:static int pagemap_range(struct dev_pagemap *pgmap, struct mhp_params *params,\nmm/memremap.c-145-\t\tint range_id, int nid)\n--\nmm/memremap.c=266=void *memremap_pages(struct dev_pagemap *pgmap, int nid)\n--\nmm/memremap.c-337-\tfor (i = 0; i \u003c nr_range; i++) {\nmm/memremap.c:338:\t\terror = pagemap_range(pgmap, \u0026params, i, nid);\nmm/memremap.c-339-\t\tif (error)\n"
} |
| 7/2 | 2026/07/20 16:12 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7652 output: 19 thoughts: 12 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Thinking Through memremap_pages** Right, so `memremap_pages` is being called by *drivers*. That's the key starting point. It immediately tells me this function is a critical piece of the kernel's memory management, specifically concerning how hardware interacts with the system's memory space. Drivers, by their very nature, are responsible for interfacing with physical devices, and often need to map physical memory regions into the virtual address space of the kernel, or potentially even user space, for DMA operations or direct access. My mind immediately starts ticking through the implications: What kind of drivers? Are we talking about network adapters mapping buffers, graphics cards handling framebuffers, or storage controllers dealing with disk sectors? The specifics matter for performance and security. Is this a common operation or something relatively rare? The frequency of its use will give a clue as to its criticality for optimization. I need to understand the constraints. How large are the memory regions being mapped? Are we talking about single pages, or potentially huge blocks? Larger regions imply potential for more complex page table manipulations and resource contention. And is it an area of memory that is shared between user and kernel, or is this mapping purely kernel space? Shared regions can open up vulnerabilities if not handled correctly. I'm also considering the potential for errors. What error handling is in place? Are we checking for valid physical addresses? What happens if the mapping fails – does it gracefully degrade, or could it lead to system instability? Security implications are another important aspect to consider here - are there checks in place to ensure that the driver can actually access the requested memory? Is there a risk of memory leaks if mappings are not properly unmapped? The return value of this function will be a key piece of information. Essentially, I'm thinking about the *why* of this function call. I need to understand what the driver is trying to *achieve* with `memremap_pages`. Knowing that will enable me to see potential performance bottlenecks and security vulnerabilities. I'm already anticipating the follow-up questions: what are the implications for NUMA systems, and how does this function handle page caching and coherence? Time to dig into the source and see what's really happening. |
| 8/2 | 2026/07/20 16:12 | tool | grepper |
0mArgs:{
"Expression": "memremap_pages"
}Results: {
"Output": "Documentation/mm/hmm.rst=274=These can be allocated and freed with::\n--\nDocumentation/mm/hmm.rst-285- pagemap.ops = \u0026device_devmem_ops;\nDocumentation/mm/hmm.rst:286: memremap_pages(\u0026pagemap, numa_node_id());\nDocumentation/mm/hmm.rst-287-\n--\nDocumentation/mm/hmm.rst-290-\nDocumentation/mm/hmm.rst:291:There are also devm_request_free_mem_region(), devm_memremap_pages(),\nDocumentation/mm/hmm.rst-292-devm_memunmap_pages(), and devm_release_mem_region() when the resources can\n--\nDocumentation/mm/memory-model.rst=141=to keep the memory pinned for active use. `ZONE_DEVICE`, via\nDocumentation/mm/memory-model.rst:142::c:func:`devm_memremap_pages`, performs just enough memory hotplug to\nDocumentation/mm/memory-model.rst-143-turn on :c:func:`pfn_to_page`, :c:func:`page_to_pfn`, and\n--\nDocumentation/mm/memory-model.rst=157=memory hotplug. Sub-section support allows for 2MB as the cross-arch\nDocumentation/mm/memory-model.rst:158:common alignment granularity for :c:func:`devm_memremap_pages`.\nDocumentation/mm/memory-model.rst-159-\n--\nDocumentation/translations/zh_CN/mm/hmm.rst=220=migrate_vma_finalize() 函数旨在使驱动程序更易于编写并集中跨驱动程序的通用代码。\n--\nDocumentation/translations/zh_CN/mm/hmm.rst-236- pagemap.ops = \u0026device_devmem_ops;\nDocumentation/translations/zh_CN/mm/hmm.rst:237: memremap_pages(\u0026pagemap, numa_node_id());\nDocumentation/translations/zh_CN/mm/hmm.rst-238-\n--\nDocumentation/translations/zh_CN/mm/hmm.rst-241-\nDocumentation/translations/zh_CN/mm/hmm.rst:242:还有devm_request_free_mem_region(), devm_memremap_pages(),\nDocumentation/translations/zh_CN/mm/hmm.rst-243-devm_memunmap_pages() 和 devm_release_mem_region() 当资源可以绑定到 ``struct device``.\n--\nDocumentation/translations/zh_CN/mm/memory-model.rst=107=ZONE_DEVICE\n--\nDocumentation/translations/zh_CN/mm/memory-model.rst-111-事实有关:这些地址范围的页面对象从未被在线标记过,而且必须对设备进行引用,而不仅仅\nDocumentation/translations/zh_CN/mm/memory-model.rst:112:是页面,以保持内存被“锁定”以便使用。 `ZONE_DEVICE` ,通过 :c:func:`devm_memremap_pages` ,\nDocumentation/translations/zh_CN/mm/memory-model.rst-113-为给定的pfns范围执行足够的内存热插拔来开启 :c:func:`pfn_to_page`,\n--\nDocumentation/translations/zh_CN/mm/memory-model.rst-122-:c:func:`arch_add_memory` ,即内存热插拔的上半部分。子段支持允许2MB作为\nDocumentation/translations/zh_CN/mm/memory-model.rst:123::c:func:`devm_memremap_pages` 的跨架构通用对齐颗粒度。\nDocumentation/translations/zh_CN/mm/memory-model.rst-124-\n--\narch/powerpc/kvm/book3s_hv_uvmem.c=1158=int kvmppc_uvmem_init(void)\n--\narch/powerpc/kvm/book3s_hv_uvmem.c-1189-\tkvmppc_uvmem_pgmap.owner = \u0026kvmppc_uvmem_pgmap;\narch/powerpc/kvm/book3s_hv_uvmem.c:1190:\taddr = memremap_pages(\u0026kvmppc_uvmem_pgmap, NUMA_NO_NODE);\narch/powerpc/kvm/book3s_hv_uvmem.c-1191-\tif (IS_ERR(addr)) {\n--\narch/x86/mm/init_64.c=964=int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,\n--\narch/x86/mm/init_64.c-976-\t/*\narch/x86/mm/init_64.c:977:\t * Special case: add_pages() is called by memremap_pages() for adding device\narch/x86/mm/init_64.c-978-\t * private pages. Do not bump up max_pfn in the device private path,\n--\ndrivers/dax/device.c=380=static int dev_dax_probe(struct dev_dax *dev_dax)\n--\ndrivers/dax/device.c-434-\t\t\torder_base_2(dev_dax-\u003ealign \u003e\u003e PAGE_SHIFT);\ndrivers/dax/device.c:435:\taddr = devm_memremap_pages(dev, pgmap);\ndrivers/dax/device.c-436-\tif (IS_ERR(addr))\n--\ndrivers/dax/fsdev.c=207=static int fsdev_dax_probe(struct dev_dax *dev_dax)\n--\ndrivers/dax/fsdev.c-273-\ndrivers/dax/fsdev.c:274:\taddr = devm_memremap_pages(dev, pgmap);\ndrivers/dax/fsdev.c-275-\tif (IS_ERR(addr))\n--\ndrivers/gpu/drm/amd/amdkfd/kfd_migrate.c=1026=int kgd2kfd_init_zone_device(struct amdgpu_device *adev)\n--\ndrivers/gpu/drm/amd/amdkfd/kfd_migrate.c-1067-\t */\ndrivers/gpu/drm/amd/amdkfd/kfd_migrate.c:1068:\tr = devm_memremap_pages(adev-\u003edev, pgmap);\ndrivers/gpu/drm/amd/amdkfd/kfd_migrate.c-1069-\tif (IS_ERR(r)) {\n--\ndrivers/gpu/drm/nouveau/nouveau_dmem.c=296=nouveau_dmem_chunk_alloc(struct nouveau_drm *drm, struct page **ppage,\n--\ndrivers/gpu/drm/nouveau/nouveau_dmem.c-332-\ndrivers/gpu/drm/nouveau/nouveau_dmem.c:333:\tptr = memremap_pages(\u0026chunk-\u003epagemap, numa_node_id());\ndrivers/gpu/drm/nouveau/nouveau_dmem.c-334-\tif (IS_ERR(ptr)) {\n--\ndrivers/gpu/drm/xe/xe_svm.c=1760=static struct xe_pagemap *xe_pagemap_create(struct xe_device *xe, struct xe_vram_region *vr)\n--\ndrivers/gpu/drm/xe/xe_svm.c-1801-\tpagemap-\u003eops = drm_pagemap_pagemap_ops_get();\ndrivers/gpu/drm/xe/xe_svm.c:1802:\taddr = devm_memremap_pages(dev, pagemap);\ndrivers/gpu/drm/xe/xe_svm.c-1803-\tif (IS_ERR(addr)) {\n--\ndrivers/hv/mshv_vtl_main.c=381=static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)\n--\ndrivers/hv/mshv_vtl_main.c-410-\t * This works best when the range is aligned; i.e. both the start and the length.\ndrivers/hv/mshv_vtl_main.c:411:\t * Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range\ndrivers/hv/mshv_vtl_main.c-412-\t * alignment exceeds the maximum supported folio order for this kernel config.\n--\ndrivers/hv/mshv_vtl_main.c-419-\ndrivers/hv/mshv_vtl_main.c:420:\taddr = devm_memremap_pages(mem_dev, pgmap);\ndrivers/hv/mshv_vtl_main.c-421-\tif (IS_ERR(addr)) {\ndrivers/hv/mshv_vtl_main.c:422:\t\tdev_err(vtl-\u003emodule_dev, \"devm_memremap_pages error: %ld\\n\", PTR_ERR(addr));\ndrivers/hv/mshv_vtl_main.c-423-\t\tkfree(pgmap);\n--\ndrivers/nvdimm/Kconfig=143=config NVDIMM_TEST_BUILD\n--\ndrivers/nvdimm/Kconfig-151-\t otherwise helps catch build errors induced by changes to the\ndrivers/nvdimm/Kconfig:152:\t core devm_memremap_pages() implementation and other\ndrivers/nvdimm/Kconfig-153-\t infrastructure.\n--\ndrivers/nvdimm/pmem.c=448=static int pmem_attach_disk(struct device *dev,\n--\ndrivers/nvdimm/pmem.c-517-\t\tpmem-\u003epgmap.ops = \u0026fsdax_pagemap_ops;\ndrivers/nvdimm/pmem.c:518:\t\taddr = devm_memremap_pages(dev, \u0026pmem-\u003epgmap);\ndrivers/nvdimm/pmem.c-519-\t\tpfn_sb = nd_pfn-\u003epfn_sb;\n--\ndrivers/nvdimm/pmem.c-530-\t\tpmem-\u003epgmap.ops = \u0026fsdax_pagemap_ops;\ndrivers/nvdimm/pmem.c:531:\t\taddr = devm_memremap_pages(dev, \u0026pmem-\u003epgmap);\ndrivers/nvdimm/pmem.c-532-\t\tbb_range = pmem-\u003epgmap.range;\n--\ndrivers/nvdimm/region_devs.c=934=EXPORT_SYMBOL(nd_region_release_lane);\n--\ndrivers/nvdimm/region_devs.c-936-/*\ndrivers/nvdimm/region_devs.c:937: * PowerPC requires this alignment for memremap_pages(). All other archs\ndrivers/nvdimm/region_devs.c-938- * should be ok with SUBSECTION_SIZE (see memremap_compat_align()).\n--\ndrivers/pci/p2pdma.c=387=int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,\n--\ndrivers/pci/p2pdma.c-436-\ndrivers/pci/p2pdma.c:437:\taddr = devm_memremap_pages(\u0026pdev-\u003edev, pgmap);\ndrivers/pci/p2pdma.c-438-\tif (IS_ERR(addr)) {\n--\ndrivers/s390/block/dcssblk.c=553=dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)\n--\ndrivers/s390/block/dcssblk.c-696-\t\tdev_info-\u003epgmap.nr_range\t= 1;\ndrivers/s390/block/dcssblk.c:697:\t\taddr = devm_memremap_pages(\u0026dev_info-\u003edev, \u0026dev_info-\u003epgmap);\ndrivers/s390/block/dcssblk.c-698-\t\tif (IS_ERR(addr)) {\n--\ndrivers/xen/unpopulated-alloc.c=37=static int fill_list(unsigned int nr_pages)\n--\ndrivers/xen/unpopulated-alloc.c-123-\ndrivers/xen/unpopulated-alloc.c:124:\tvaddr = memremap_pages(pgmap, NUMA_NO_NODE);\ndrivers/xen/unpopulated-alloc.c-125-\tif (IS_ERR(vaddr)) {\n--\nfs/fuse/virtio_fs.c=1076=static int virtio_fs_setup_dax(struct virtio_device *vdev, struct virtio_fs *fs)\n--\nfs/fuse/virtio_fs.c-1116-\t/* Ideally we would directly use the PCI BAR resource but\nfs/fuse/virtio_fs.c:1117:\t * devm_memremap_pages() wants its own copy in pgmap. So\nfs/fuse/virtio_fs.c-1118-\t * initialize a struct resource from scratch (only the start\n--\nfs/fuse/virtio_fs.c-1126-\nfs/fuse/virtio_fs.c:1127:\tfs-\u003ewindow_kaddr = devm_memremap_pages(\u0026vdev-\u003edev, pgmap);\nfs/fuse/virtio_fs.c-1128-\tif (IS_ERR(fs-\u003ewindow_kaddr))\n--\ninclude/linux/memremap.h=77=struct dev_pagemap_ops {\n--\ninclude/linux/memremap.h-115- * @altmap: pre-allocated/reserved memory for vmemmap allocations\ninclude/linux/memremap.h:116: * @ref: reference count that pins the devm_memremap_pages() mapping\ninclude/linux/memremap.h-117- * @done: completion for @ref\n--\ninclude/linux/memremap.h=227=void zone_device_page_init(struct page *page, struct dev_pagemap *pgmap,\ninclude/linux/memremap.h-228-\t\t\t unsigned int order);\ninclude/linux/memremap.h:229:void *memremap_pages(struct dev_pagemap *pgmap, int nid);\ninclude/linux/memremap.h-230-void memunmap_pages(struct dev_pagemap *pgmap);\ninclude/linux/memremap.h:231:void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap);\ninclude/linux/memremap.h-232-void devm_memunmap_pages(struct device *dev, struct dev_pagemap *pgmap);\n--\ninclude/linux/memremap.h=247=static inline void zone_device_private_split_cb(struct folio *original_folio,\n--\ninclude/linux/memremap.h-264-#else\ninclude/linux/memremap.h:265:static inline void *devm_memremap_pages(struct device *dev,\ninclude/linux/memremap.h-266-\t\tstruct dev_pagemap *pgmap)\n--\ninclude/linux/memremap.h-268-\t/*\ninclude/linux/memremap.h:269:\t * Fail attempts to call devm_memremap_pages() without\ninclude/linux/memremap.h-270-\t * ZONE_DEVICE support enabled, this requires callers to fall\n--\ninclude/linux/memremap.h=287=static inline bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn)\n--\ninclude/linux/memremap.h-291-\ninclude/linux/memremap.h:292:/* when memremap_pages() is disabled all archs can remap a single page */\ninclude/linux/memremap.h-293-static inline unsigned long memremap_compat_align(void)\n--\nlib/test_hmm.c=558=static int dmirror_allocate_chunk(struct dmirror_device *mdevice,\n--\nlib/test_hmm.c-615-\t}\nlib/test_hmm.c:616:\tptr = memremap_pages(\u0026devmem-\u003epagemap, numa_node_id());\nlib/test_hmm.c-617-\tif (IS_ERR_OR_NULL(ptr)) {\n--\nmm/memremap.c=17=static DEFINE_XARRAY(pgmap_array);\n--\nmm/memremap.c-19-/*\nmm/memremap.c:20: * The memremap() and memremap_pages() interfaces are alternately used\nmm/memremap.c-21- * to map persistent memory namespaces. These interfaces place different\nmm/memremap.c-22- * constraints on the alignment and size of the mapping (namespace).\nmm/memremap.c:23: * memremap() can map individual PAGE_SIZE pages. memremap_pages() can\nmm/memremap.c-24- * only map subsections (2MB), and at least one architecture (PowerPC)\nmm/memremap.c:25: * the minimum mapping granularity of memremap_pages() is 16MB.\nmm/memremap.c-26- *\n--\nmm/memremap.c=130=EXPORT_SYMBOL_GPL(memunmap_pages);\nmm/memremap.c-131-\nmm/memremap.c:132:static void devm_memremap_pages_release(void *data)\nmm/memremap.c-133-{\n--\nmm/memremap.c=144=static int pagemap_range(struct dev_pagemap *pgmap, struct mhp_params *params,\n--\nmm/memremap.c-261-/*\nmm/memremap.c:262: * Not device managed version of devm_memremap_pages, undone by\nmm/memremap.c:263: * memunmap_pages(). Please use devm_memremap_pages if you have a struct\nmm/memremap.c-264- * device available.\nmm/memremap.c-265- */\nmm/memremap.c:266:void *memremap_pages(struct dev_pagemap *pgmap, int nid)\nmm/memremap.c-267-{\n--\nmm/memremap.c-351-}\nmm/memremap.c:352:EXPORT_SYMBOL_GPL(memremap_pages);\nmm/memremap.c-353-\nmm/memremap.c-354-/**\nmm/memremap.c:355: * devm_memremap_pages - remap and provide memmap backing for the given resource\nmm/memremap.c-356- * @dev: hosting device for @res\n--\nmm/memremap.c-367- * 'live' on entry and will be killed and reaped at\nmm/memremap.c:368: * devm_memremap_pages_release() time, or if this routine fails.\nmm/memremap.c-369- *\n--\nmm/memremap.c-373- */\nmm/memremap.c:374:void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)\nmm/memremap.c-375-{\n--\nmm/memremap.c-378-\nmm/memremap.c:379:\tret = memremap_pages(pgmap, dev_to_node(dev));\nmm/memremap.c-380-\tif (IS_ERR(ret))\n--\nmm/memremap.c-382-\nmm/memremap.c:383:\terror = devm_add_action_or_reset(dev, devm_memremap_pages_release,\nmm/memremap.c-384-\t\t\tpgmap);\n--\nmm/memremap.c-388-}\nmm/memremap.c:389:EXPORT_SYMBOL_GPL(devm_memremap_pages);\nmm/memremap.c-390-\nmm/memremap.c=391=void devm_memunmap_pages(struct device *dev, struct dev_pagemap *pgmap)\nmm/memremap.c-392-{\nmm/memremap.c:393:\tdevm_release_action(dev, devm_memremap_pages_release, pgmap);\nmm/memremap.c-394-}\n--\nmm/sparse-vmemmap.c=402=int __meminit vmemmap_populate_hugepages(unsigned long start, unsigned long end,\n--\nmm/sparse-vmemmap.c-459- *\nmm/sparse-vmemmap.c:460: * Note that memremap_pages() resets @nr_range value and will increment\nmm/sparse-vmemmap.c-461- * it after each range successful onlining. Thus the value or @nr_range\n--\ntools/testing/nvdimm/Kbuild=13=ldflags-y += --wrap=__release_region\ntools/testing/nvdimm/Kbuild:14:ldflags-y += --wrap=devm_memremap_pages\ntools/testing/nvdimm/Kbuild-15-ldflags-y += --wrap=insert_resource\n--\ntools/testing/nvdimm/test/iomap.c=108=static void dev_pagemap_percpu_release(struct percpu_ref *ref)\n--\ntools/testing/nvdimm/test/iomap.c-114-\ntools/testing/nvdimm/test/iomap.c:115:void *__wrap_devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)\ntools/testing/nvdimm/test/iomap.c-116-{\n--\ntools/testing/nvdimm/test/iomap.c-121-\tif (!nfit_res)\ntools/testing/nvdimm/test/iomap.c:122:\t\treturn devm_memremap_pages(dev, pgmap);\ntools/testing/nvdimm/test/iomap.c-123-\n--\ntools/testing/nvdimm/test/iomap.c-134-}\ntools/testing/nvdimm/test/iomap.c:135:EXPORT_SYMBOL_GPL(__wrap_devm_memremap_pages);\ntools/testing/nvdimm/test/iomap.c-136-\n--\ntools/testing/nvdimm/test/nfit_test.h=212=void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,\ntools/testing/nvdimm/test/nfit_test.h-213-\t\tsize_t size, unsigned long flags);\ntools/testing/nvdimm/test/nfit_test.h:214:void *__wrap_devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap);\ntools/testing/nvdimm/test/nfit_test.h-215-void *__wrap_memremap(resource_size_t offset, size_t size,\n"
} |
| 9/2 | 2026/07/20 16:12 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14100 output: 20 thoughts: 225 Thoughts: **Analyzing Potential Attack Surfaces with `devm_memremap_pages`** Okay, so I'm digging into `devm_memremap_pages`. My initial scan shows this function is pretty widely used across various drivers. Specifically, I see it's called by `drivers/dax/device.c` within `dev_dax_probe`, `drivers/dax/fsdev.c` during `fsdev_dax_probe`, `drivers/nvdimm/pmem.c` in `pmem_attach_disk`, `drivers/pci/p2pdma.c` within `pci_p2pdma_add_resource`, and also in `fs/fuse/virtio_fs.c` during `virtio_fs_setup_dax`. Immediately, I'm thinking about Syzkaller and its potential to exploit this code path. I'm almost certain I can trigger either `virtio_fs_setup_dax`, `dev_dax_probe`, or `pci_p2pdma_add_resource` with fuzzing. Wait, hold on. This reminds me of the relationship between `memmap_init_zone_device` and `memmap_init_compound`. I just want to be sure about the calling order. Let me quickly double-check – I thought `memmap_init_compound` was called from `memmap_init_zone_device`, and I'm right, that's it. Ok. Now, let's take a closer look at `memmap_init_compound`... |
| 10/2 | 2026/07/20 16:12 | tool | grepper |
0mArgs:{
"Expression": "memmap_init_compound"
}Results: {
"Output": "mm/mm_init.c=1115=static inline unsigned long compound_nr_pages(unsigned long pfn,\n--\nmm/mm_init.c-1130-\nmm/mm_init.c:1131:static void __ref memmap_init_compound(struct page *head,\nmm/mm_init.c-1132-\t\t\t\t unsigned long head_pfn,\n--\nmm/mm_init.c=1172=void __ref memmap_init_zone_device(struct zone *zone,\n--\nmm/mm_init.c-1223-\nmm/mm_init.c:1224:\t\tmemmap_init_compound(page, pfn, zone_idx, nid, pgmap,\nmm/mm_init.c-1225-\t\t\t\t compound_nr_pages(pfn, altmap, pgmap));\n"
} |
| 11/2 | 2026/07/20 16:12 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14916 output: 24 thoughts: 352 Thoughts: **Analyzing the Page Initialization Optimization**
Okay, so this patch is digging into `memmap_init_zone_device`, which in turn calls `memmap_init_compound`. The core change is swapping out the original initialization routines for `memcpy_nontemporal`, and on x86, that means using `memcpy_flushcache`, which ultimately translates to `movnti` instructions. This is definitely a functional change – it's fundamentally altering how memory pages are initialized.
The immediate question, as always, is whether this warrants fuzzing. The answer is a resounding *yes*. Anytime you're touching memory initialization and introducing non-temporal stores, you're potentially opening the door to subtle but devastating bugs. Ordering issues with non-temporal stores, incorrect sizes, any deviation from the expected behavior, and there could be a wide range of memory corruption issues.
Wait, let me just double-check something. So, on x86, `memcpy_flushcache` is implemented with `movnti_8`, `movnti_16`, `movnti_32`, and `movnti_64` for different data sizes. Okay, that confirms the core change involves those instructions. I'm going to scan the patch again just to double check that I didn't miss something.
```c
+static __always_inline void movnti_8(void *dst, const void *src)
+{
+ asm volatile("movntiq %1, %0"
+ : "=m"(*(u64 *)dst)
+ : "r"(*(const u64 *)src)
+ : "memory");
+}
```
Okay, yep, that's what I thought. Functionally, it is exactly the `movnti` instructions that the patch is implementing, so that's the relevant change.
Now, let me just confirm the relevant configurations. We know `CONFIG_ZONE_DEVICE` is needed for `memmap_init_zone_device`. And to use `memcpy_flushcache` on x86, we need `CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE`. Okay, time to check `arch/x86/Kconfig` to see exactly what that config entails.
|
| 12/2 | 2026/07/20 16:13 | tool | grepper |
0mArgs:{
"Expression": "ARCH_HAS_UACCESS_FLUSHCACHE"
}Results: {
"Output": "arch/arm64/Kconfig=1922=config ARM64_PMEM\n--\narch/arm64/Kconfig-1924-\tselect ARCH_HAS_PMEM_API\narch/arm64/Kconfig:1925:\tselect ARCH_HAS_UACCESS_FLUSHCACHE\narch/arm64/Kconfig-1926-\thelp\n--\narch/arm64/include/asm/string.h=44=extern void *__memset(void *, int, __kernel_size_t);\narch/arm64/include/asm/string.h-45-\narch/arm64/include/asm/string.h:46:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\narch/arm64/include/asm/string.h-47-#define __HAVE_ARCH_MEMCPY_FLUSHCACHE\n--\narch/arm64/include/asm/uaccess.h=475=extern __must_check long strnlen_user(const char __user *str, long n);\narch/arm64/include/asm/uaccess.h-476-\narch/arm64/include/asm/uaccess.h:477:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\narch/arm64/include/asm/uaccess.h-478-extern unsigned long __must_check __copy_user_flushcache(void *to, const void __user *from, unsigned long n);\n--\narch/arm64/lib/Makefile=2=lib-y\t\t:= clear_user.o delay.o copy_from_user.o\t\t\\\n--\narch/arm64/lib/Makefile-7-\narch/arm64/lib/Makefile:8:lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o\narch/arm64/lib/Makefile-9-\n--\narch/powerpc/Kconfig=118=config PPC\n--\narch/powerpc/Kconfig-158-\tselect ARCH_HAS_TICK_BROADCAST\t\tif GENERIC_CLOCKEVENTS_BROADCAST\narch/powerpc/Kconfig:159:\tselect ARCH_HAS_UACCESS_FLUSHCACHE\narch/powerpc/Kconfig-160-\tselect ARCH_HAS_UBSAN\n--\narch/powerpc/lib/pmem.c=64=EXPORT_SYMBOL_GPL(arch_invalidate_pmem);\n--\narch/powerpc/lib/pmem.c-66-/*\narch/powerpc/lib/pmem.c:67: * CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE symbols\narch/powerpc/lib/pmem.c-68- */\n--\narch/x86/Kconfig=58=config X86\n--\narch/x86/Kconfig-102-\tselect ARCH_HAS_NONLEAF_PMD_YOUNG\tif PGTABLE_LEVELS \u003e 2\narch/x86/Kconfig:103:\tselect ARCH_HAS_UACCESS_FLUSHCACHE\tif X86_64\narch/x86/Kconfig-104-\tselect ARCH_HAS_COPY_MC\t\t\tif X86_64\n--\narch/x86/include/asm/string_64.h=80=int strcmp(const char *cs, const char *ct);\narch/x86/include/asm/string_64.h-81-\narch/x86/include/asm/string_64.h:82:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\narch/x86/include/asm/string_64.h-83-#define __HAVE_ARCH_MEMCPY_FLUSHCACHE 1\n--\narch/x86/lib/usercopy_64.c-17-\narch/x86/lib/usercopy_64.c:18:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\narch/x86/lib/usercopy_64.c-19-/**\n--\ndrivers/nvdimm/pmem.c=448=static int pmem_attach_disk(struct device *dev,\n--\ndrivers/nvdimm/pmem.c-493-\tfua = nvdimm_has_flush(nd_region);\ndrivers/nvdimm/pmem.c:494:\tif (!IS_ENABLED(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) || fua \u003c 0) {\ndrivers/nvdimm/pmem.c-495-\t\tdev_warn(dev, \"unable to guarantee persistence of writes\\n\");\n--\ninclude/linux/uio.h=261=bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i)\n--\ninclude/linux/uio.h-269-\ninclude/linux/uio.h:270:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\ninclude/linux/uio.h-271-/*\n--\ninclude/linux/uio.h-273- * _copy_from_iter_flushcache() than _copy_from_iter_nocache() must check for\ninclude/linux/uio.h:274: * IS_ENABLED(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) before assuming that the\ninclude/linux/uio.h-275- * destination is flushed from the cache on return.\n--\nlib/Kconfig=542=config UACCESS_MEMCPY\n--\nlib/Kconfig-544-\nlib/Kconfig:545:config ARCH_HAS_UACCESS_FLUSHCACHE\nlib/Kconfig-546-\tbool\n--\nlib/iov_iter.c=292=EXPORT_SYMBOL(_copy_from_iter_nocache);\nlib/iov_iter.c-293-\nlib/iov_iter.c:294:#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE\nlib/iov_iter.c-295-static __always_inline\n"
} |
| 13/2 | 2026/07/20 16:13 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17273 output: 18 thoughts: 65 Thoughts: **Examining Kernel Configuration Dependencies** Okay, so `CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE` is automatically selected when the x86_64 architecture is chosen. That's good to know, simplifies things somewhat. Now, I see that `memmap_init_zone_device` requires `CONFIG_ZONE_DEVICE`. Hmm, I should probably double-check the implications of that. Let me quickly jump into `mm/Kconfig` to refresh my memory on what `CONFIG_ZONE_DEVICE` actually enables, and what its dependencies might be. I need to understand this fully to assess the broader impact on the system. |
| 14/2 | 2026/07/20 16:13 | tool | grepper |
0mArgs:{
"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"
} |
| 15/2 | 2026/07/20 16:13 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17579 output: 28 thoughts: 810 Thoughts: **Fuzzing Target Identification: ZONE_DEVICE Memory Initialization** Okay, let's break this down. My initial thought is to zero in on `memmap_init_compound` and `memmap_init_zone_device` within `mm/mm_init.c`. The patch modifies these functions, and they're core to ZONE_DEVICE memory initialization. That's our starting point for focused fuzzing. My mind then quickly jumps to how we can actually *trigger* these functions. `memmap_init_zone_device` gets called during device probe, specifically through calls like `devm_memremap_pages`. The key question is whether we can reach this via a syscall. Yes, that's the angle! `mmap` of `/dev/dax` is the obvious first candidate, or perhaps an `ioctl` that adds memory. Also, `memremap_pages` in some driver might be vulnerable and triggerable via syzkaller. For example, `mshv_vtl_ioctl_add_vtl0_mem` in `drivers/hv/mshv_vtl_main.c` calls `devm_memremap_pages`. This is a solid lead. Also, `virtio_fs_setup_dax` in `fs/fuse/virtio_fs.c` calls `devm_memremap_pages`. So, we've got multiple potential entry points. This looks promising. Now, let's circle back to the actual code. The patch introduces `memcpy_nontemporal` and it's used in `mm/mm_init.c`. This is new, which is a good sign for uncovering bugs. It's also defined in `arch/x86/include/asm/string_64.h` with the `movnti_*` functions, and `include/linux/mm.h` with `set_page_section_from_pfn`, and `include/linux/string.h` for fallback. These are changes we need to keep in mind. Digging deeper, `zone_device_page_init_from_template` within `mm/mm_init.c` seems particularly interesting because it uses `memcpy_nontemporal`. The function's structure is also helpful and it's called by `memmap_init_compound` and `memmap_init_zone_device`. Aha! `memmap_init_compound` is static, which limits its exposure, but `memmap_init_zone_device` is exported. That's a good candidate for inclusion in FocusSymbols and also `memmap_init_compound`. Finally, configuration. We need `CONFIG_ZONE_DEVICE` for sure. The x86-specific `movnti` instructions are implicitly tied to `CONFIG_X86_64` but `ZONE_DEVICE` should be sufficient. Wait, `ZONE_DEVICE` depends on `MEMORY_HOTPLUG`, `MEMORY_HOTREMOVE`, and `SPARSEMEM_VMEMMAP`. We need to verify that in `mm/Kconfig`. |
| 16/2 | 2026/07/20 16:13 | tool | grepper |
0mArgs:{
"Expression": "config ZONE_DEVICE",
"PathPrefix": "mm/Kconfig"
}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"
} |
| 17/2 | 2026/07/20 16:13 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19180 output: 33 thoughts: 18 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into the Kernel Configuration Landscape** Okay, so I need to get a handle on how this particular configuration option is handled. Let's start by zeroing in on `mm/Kconfig`. I'm thinking around line 1236 should be a good starting point, given the context of what I'm dealing with. I have a hunch it's related to some memory management feature. Let's see what the Kconfig entries reveal about the conditional compilation, dependencies, and any accompanying documentation. I want to quickly grasp the relevant context and ensure I have the right dependencies in mind for subsequent analysis. I'm hoping to uncover the underlying logic for this feature. |
| 18/2 | 2026/07/20 16:13 | tool | read-file |
0mArgs:{
"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"
} |
| 19/2 | 2026/07/20 16:13 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 19705 output: 38 thoughts: 129 Thoughts: **Analyzing the Memory Configuration** Okay, so `ZONE_DEVICE` seems to be the key configuration option here. My initial thought is, are there any *other* relevant configs I should be considering? The patch also modifies `arch/x86/include/asm/string_64.h`, which is interesting, so I need to keep that in mind. The `memcpy_flushcache` function is defined conditionally, dependent on `CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE`. Now, let me see... and that macro is specifically selected when `X86_64` is enabled. Therefore, it confirms that `ZONE_DEVICE` is the primary config that enables the feature I'm examining. To confirm my understanding, the next logical step is to delve into the `memmap_init_zone_device` function. I will need to check the definition of that function, it should be in `mm/mm_init.c`. That should give me the deeper context I require. |
| 20/2 | 2026/07/20 16:13 | tool | grepper |
0mArgs:{
"Expression": "void __ref memmap_init_zone_device",
"PathPrefix": "mm/mm_init.c"
}Results: {
"Output": "mm/mm_init.c=1131=static void __ref memmap_init_compound(struct page *head,\n--\nmm/mm_init.c-1171-\nmm/mm_init.c:1172:void __ref memmap_init_zone_device(struct zone *zone,\nmm/mm_init.c-1173-\t\t\t\t unsigned long start_pfn,\n"
} |
| 21/2 | 2026/07/20 16:13 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20198 output: 129 thoughts: 414 Thoughts: **Analyzing a ZONE_DEVICE Memory Optimization Patch** Okay, so I'm looking at this patch and my initial thought is, "Wait, `memmap_init_compound` is static, isn't it?" Then, I remember syzkaller can use static functions as long as they're in the symbol table, which they usually are unless they're inlined. So, let's check if `memmap_init_compound` is inlined. Yep, it's declared as `static void __ref memmap_init_compound(struct page *head, ...)`, so no explicit `inline` keyword. Now, what about `zone_device_page_init_from_template`? I'll check that one too. Okay, it's also `static void zone_device_page_init_from_template(...)`. No explicit `inline` there either, but the compiler *could* be inlining it. To keep things simple and reliable, I'll just focus on using `memmap_init_zone_device` and `memmap_init_compound` directly. Let's quickly review the patch again. Ah yes, it's optimizing the initialization of `struct page` for ZONE_DEVICE memory using non-temporal stores, specifically `memcpy_nontemporal`. This is definitely a functional change, it's not just cosmetic. And, crucially, this is reachable through device probes, things like DAX, PMEM, and virtio-fs DAX. This makes it a solid candidate for fuzzing. My reasoning is that the patch optimizes `struct page` initialization for ZONE_DEVICE memory using non-temporal stores, directly affecting memory management initialization paths and x86 string routines. Since it's reachable through device probing, which are pretty common, this is definitely something we need to fuzz. Just to be absolutely sure, let's double check that `memmap_init_compound` is the correct name. Yes, `memmap_init_compound`. Right, let's call the set-results tool. |
| 22/2 | 2026/07/20 16:13 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"ZONE_DEVICE"
],
"FocusSymbols": [
"memmap_init_zone_device",
"memmap_init_compound"
],
"Reasoning": "The patch introduces a functional optimization for initializing `struct page` structures for ZONE_DEVICE memory using non-temporal stores (`memcpy_nontemporal`). This modifies core memory management initialization paths and x86 string routines. It is reachable when probing devices that use ZONE_DEVICE memory (e.g., DAX, PMEM, virtio-fs DAX).",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"ZONE_DEVICE"
],
"FocusSymbols": [
"memmap_init_zone_device",
"memmap_init_compound"
],
"Reasoning": "The patch introduces a functional optimization for initializing `struct page` structures for ZONE_DEVICE memory using non-temporal stores (`memcpy_nontemporal`). This modifies core memory management initialization paths and x86 string routines. It is reachable when probing devices that use ZONE_DEVICE memory (e.g., DAX, PMEM, virtio-fs DAX).",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|