AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/10/03 13:32 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "All changes in this patch series are strictly confined to the SPARC architecture (arch/sparc/), making them unreachable and non-compilable on the target amd64 architecture.",
  "WorthFuzzing": false
}

1/1 2026/10/03 13:32 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit dd1ff8d0996f4549dd916d7fb2abfe959de7dbd0\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Oct 3 13:32:55 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h\nindex 4eeb938f3e61c..6c7e38c993086 100644\n--- a/arch/sparc/include/asm/mmu_64.h\n+++ b/arch/sparc/include/asm/mmu_64.h\n@@ -115,6 +115,11 @@ typedef struct {\n \tbool\t\t\tadi;\n \ttag_storage_desc_t\t*tag_store;\n \tspinlock_t\t\ttag_lock;\n+\t/* TSB being replaced by tsb_grow(), still used by CPUs that\n+\t * have not run tsb_sync() yet.\n+\t */\n+\tstruct tsb\t\t*tsb_old[MM_NUM_TSBS];\n+\tunsigned long\t\ttsb_old_nentries[MM_NUM_TSBS];\n } mm_context_t;\n \n #endif /* !__ASSEMBLER__ */\ndiff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h\nindex 0837ebbc5dce6..16e39f5991ed9 100644\n--- a/arch/sparc/include/asm/pgtable_64.h\n+++ b/arch/sparc/include/asm/pgtable_64.h\n@@ -971,6 +971,9 @@ struct seq_file;\n void mmu_info(struct seq_file *);\n \n struct vm_area_struct;\n+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS\n+int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,\n+\t\t\t  pte_t *ptep, pte_t entry, int dirty);\n void update_mmu_cache_range(struct vm_fault *, struct vm_area_struct *,\n \t\tunsigned long addr, pte_t *ptep, unsigned int nr);\n #define update_mmu_cache(vma, addr, ptep) \\\ndiff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h\nindex 6133306ba59ac..1e2c7e567a2d8 100644\n--- a/arch/sparc/include/asm/tlbflush_64.h\n+++ b/arch/sparc/include/asm/tlbflush_64.h\n@@ -48,6 +48,16 @@ void __flush_tlb_all(void);\n void __flush_tlb_page(unsigned long context, unsigned long vaddr);\n void __flush_tlb_kernel_range(unsigned long start, unsigned long end);\n \n+struct vm_area_struct;\n+#define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault\n+void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,\n+\t\t\t\t  unsigned long address, pte_t *ptep);\n+#ifdef CONFIG_TRANSPARENT_HUGEPAGE\n+#define flush_tlb_fix_spurious_fault_pmd flush_tlb_fix_spurious_fault_pmd\n+void flush_tlb_fix_spurious_fault_pmd(struct vm_area_struct *vma,\n+\t\t\t\t      unsigned long address, pmd_t *pmdp);\n+#endif\n+\n #ifndef CONFIG_SMP\n \n static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)\ndiff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c\nindex 6d9dd5eb13287..006bee88fee50 100644\n--- a/arch/sparc/mm/tlb.c\n+++ b/arch/sparc/mm/tlb.c\n@@ -22,6 +22,41 @@\n \n static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);\n \n+int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,\n+\t\t\t  pte_t *ptep, pte_t entry, int dirty)\n+{\n+\tint changed = !pte_same(ptep_get(ptep), entry);\n+\n+\tif (changed)\n+\t\tset_pte_at(vma-\u003evm_mm, address, ptep, entry);\n+\treturn changed;\n+}\n+\n+/* Only base pages get here: hugetlb uses huge_ptep_set_access_flags() and\n+ * THP the PMD variant below.\n+ */\n+void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,\n+\t\t\t\t  unsigned long address, pte_t *ptep)\n+{\n+\taddress \u0026= PAGE_MASK;\n+\tflush_tsb_user_page(vma-\u003evm_mm, address, PAGE_SHIFT);\n+\tglobal_flush_tlb_page(vma-\u003evm_mm, address);\n+}\n+\n+#ifdef CONFIG_TRANSPARENT_HUGEPAGE\n+void flush_tlb_fix_spurious_fault_pmd(struct vm_area_struct *vma,\n+\t\t\t\t      unsigned long address, pmd_t *pmdp)\n+{\n+\tstruct mm_struct *mm = vma-\u003evm_mm;\n+\n+\taddress \u0026= HPAGE_MASK;\n+\tflush_tsb_user_page(mm, address, REAL_HPAGE_SHIFT);\n+\tflush_tsb_user_page(mm, address + REAL_HPAGE_SIZE, REAL_HPAGE_SHIFT);\n+\tglobal_flush_tlb_page(mm, address);\n+\tglobal_flush_tlb_page(mm, address + REAL_HPAGE_SIZE);\n+}\n+#endif\n+\n void flush_tlb_pending(void)\n {\n \tstruct tlb_batch *tb = \u0026get_cpu_var(tlb_batch);\ndiff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c\nindex 5fe52a64c7e70..d73cc1fb05755 100644\n--- a/arch/sparc/mm/tsb.c\n+++ b/arch/sparc/mm/tsb.c\n@@ -135,6 +135,20 @@ void flush_tsb_user(struct tlb_batch *tb)\n \t\t\t__flush_huge_tsb_one(tb, PAGE_SHIFT, base, nentries,\n \t\t\t\t\t     tb-\u003ehugepage_shift);\n #endif\n+\t\tif (mm-\u003econtext.tsb_old[MM_TSB_BASE]) {\n+\t\t\tbase = (unsigned long) mm-\u003econtext.tsb_old[MM_TSB_BASE];\n+\t\t\tnentries = mm-\u003econtext.tsb_old_nentries[MM_TSB_BASE];\n+\t\t\tif (tlb_type == cheetah_plus || tlb_type == hypervisor)\n+\t\t\t\tbase = __pa(base);\n+\t\t\tif (tb-\u003ehugepage_shift == PAGE_SHIFT)\n+\t\t\t\t__flush_tsb_one(tb, PAGE_SHIFT, base, nentries);\n+#if defined(CONFIG_HUGETLB_PAGE)\n+\t\t\telse\n+\t\t\t\t__flush_huge_tsb_one(tb, PAGE_SHIFT, base,\n+\t\t\t\t\t\t     nentries,\n+\t\t\t\t\t\t     tb-\u003ehugepage_shift);\n+#endif\n+\t\t}\n \t}\n #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)\n \telse if (mm-\u003econtext.tsb_block[MM_TSB_HUGE].tsb) {\n@@ -144,6 +158,14 @@ void flush_tsb_user(struct tlb_batch *tb)\n \t\t\tbase = __pa(base);\n \t\t__flush_huge_tsb_one(tb, REAL_HPAGE_SHIFT, base, nentries,\n \t\t\t\t     tb-\u003ehugepage_shift);\n+\t\tif (mm-\u003econtext.tsb_old[MM_TSB_HUGE]) {\n+\t\t\tbase = (unsigned long) mm-\u003econtext.tsb_old[MM_TSB_HUGE];\n+\t\t\tnentries = mm-\u003econtext.tsb_old_nentries[MM_TSB_HUGE];\n+\t\t\tif (tlb_type == cheetah_plus || tlb_type == hypervisor)\n+\t\t\t\tbase = __pa(base);\n+\t\t\t__flush_huge_tsb_one(tb, REAL_HPAGE_SHIFT, base,\n+\t\t\t\t\t     nentries, tb-\u003ehugepage_shift);\n+\t\t}\n \t}\n #endif\n \tspin_unlock_irqrestore(\u0026mm-\u003econtext.lock, flags);\n@@ -169,6 +191,21 @@ void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr,\n \t\t\t__flush_huge_tsb_one_entry(base, vaddr, PAGE_SHIFT,\n \t\t\t\t\t\t   nentries, hugepage_shift);\n #endif\n+\t\tif (mm-\u003econtext.tsb_old[MM_TSB_BASE]) {\n+\t\t\tbase = (unsigned long) mm-\u003econtext.tsb_old[MM_TSB_BASE];\n+\t\t\tnentries = mm-\u003econtext.tsb_old_nentries[MM_TSB_BASE];\n+\t\t\tif (tlb_type == cheetah_plus || tlb_type == hypervisor)\n+\t\t\t\tbase = __pa(base);\n+\t\t\tif (hugepage_shift == PAGE_SHIFT)\n+\t\t\t\t__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT,\n+\t\t\t\t\t\t      nentries);\n+#if defined(CONFIG_HUGETLB_PAGE)\n+\t\t\telse\n+\t\t\t\t__flush_huge_tsb_one_entry(base, vaddr,\n+\t\t\t\t\t\t\t   PAGE_SHIFT, nentries,\n+\t\t\t\t\t\t\t   hugepage_shift);\n+#endif\n+\t\t}\n \t}\n #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)\n \telse if (mm-\u003econtext.tsb_block[MM_TSB_HUGE].tsb) {\n@@ -178,6 +215,15 @@ void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr,\n \t\t\tbase = __pa(base);\n \t\t__flush_huge_tsb_one_entry(base, vaddr, REAL_HPAGE_SHIFT,\n \t\t\t\t\t   nentries, hugepage_shift);\n+\t\tif (mm-\u003econtext.tsb_old[MM_TSB_HUGE]) {\n+\t\t\tbase = (unsigned long) mm-\u003econtext.tsb_old[MM_TSB_HUGE];\n+\t\t\tnentries = mm-\u003econtext.tsb_old_nentries[MM_TSB_HUGE];\n+\t\t\tif (tlb_type == cheetah_plus || tlb_type == hypervisor)\n+\t\t\t\tbase = __pa(base);\n+\t\t\t__flush_huge_tsb_one_entry(base, vaddr,\n+\t\t\t\t\t\t   REAL_HPAGE_SHIFT, nentries,\n+\t\t\t\t\t\t   hugepage_shift);\n+\t\t}\n \t}\n #endif\n \tspin_unlock_irqrestore(\u0026mm-\u003econtext.lock, flags);\n@@ -460,17 +506,26 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)\n \t * accessing the old TSB via TLB miss handling.  This is OK\n \t * because those actions are just propagating state from the\n \t * Linux page tables into the TSB, page table mappings are not\n-\t * being changed.  If a real fault occurs, the processor will\n-\t * synchronize with us when it hits flush_tsb_user(), this is\n-\t * also true for the case where vmscan is modifying the page\n-\t * tables.  The only thing we need to be careful with is to\n-\t * skip any locked TSB entries during copy_tsb().\n+\t * being changed.  Processors keep using the old TSB until they\n+\t * have run tsb_context_switch(), so the old TSB is recorded in\n+\t * tsb_old[] and flushed along with the new one until the\n+\t * smp_tsb_sync() below has returned.  The only thing we need\n+\t * to be careful with is to skip any locked TSB entries during\n+\t * copy_tsb().\n \t *\n \t * When we finish committing to the new TSB, we have to drop\n \t * the lock and ask all other cpus running this address space\n \t * to run tsb_context_switch() to see the new TSB table.\n+\t *\n+\t * An earlier grow of this TSB may still be waiting for the\n+\t * other cpus; its old TSB has to stay recorded until then.\n \t */\n \tspin_lock_irqsave(\u0026mm-\u003econtext.lock, flags);\n+\twhile (mm-\u003econtext.tsb_old[tsb_index]) {\n+\t\tspin_unlock_irqrestore(\u0026mm-\u003econtext.lock, flags);\n+\t\tcond_resched();\n+\t\tspin_lock_irqsave(\u0026mm-\u003econtext.lock, flags);\n+\t}\n \n \told_tsb = mm-\u003econtext.tsb_block[tsb_index].tsb;\n \told_cache_index =\n@@ -511,6 +566,11 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)\n \t\t\tPAGE_SHIFT : REAL_HPAGE_SHIFT);\n \t}\n \n+\tif (old_tsb) {\n+\t\tmm-\u003econtext.tsb_old[tsb_index] = old_tsb;\n+\t\tmm-\u003econtext.tsb_old_nentries[tsb_index] =\n+\t\t\tmm-\u003econtext.tsb_block[tsb_index].tsb_nentries;\n+\t}\n \tmm-\u003econtext.tsb_block[tsb_index].tsb = new_tsb;\n \tsetup_tsb_params(mm, tsb_index, new_size);\n \n@@ -529,6 +589,12 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)\n \t\tpreempt_enable();\n \n \t\t/* Now it is safe to free the old tsb.  */\n+\t\tspin_lock_irqsave(\u0026mm-\u003econtext.lock, flags);\n+\t\tif (mm-\u003econtext.tsb_old[tsb_index] == old_tsb) {\n+\t\t\tmm-\u003econtext.tsb_old[tsb_index] = NULL;\n+\t\t\tmm-\u003econtext.tsb_old_nentries[tsb_index] = 0;\n+\t\t}\n+\t\tspin_unlock_irqrestore(\u0026mm-\u003econtext.lock, flags);\n \t\tkmem_cache_free(tsb_caches[old_cache_index], old_tsb);\n \t}\n }\n@@ -566,8 +632,10 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)\n \t * us, so we need to zero out the TSB pointer or else tsb_grow()\n \t * will be confused and think there is an older TSB to free up.\n \t */\n-\tfor (i = 0; i \u003c MM_NUM_TSBS; i++)\n+\tfor (i = 0; i \u003c MM_NUM_TSBS; i++) {\n \t\tmm-\u003econtext.tsb_block[i].tsb = NULL;\n+\t\tmm-\u003econtext.tsb_old[i] = NULL;\n+\t}\n \n \t/* If this is fork, inherit the parent's TSB size.  We would\n \t * grow it to that size on the first page fault anyways.\n"
}

2/1 2026/10/03 13:32 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "All changes in this patch series are strictly confined to the SPARC architecture (arch/sparc/), making them unreachable and non-compilable on the target amd64 architecture.",
  "WorthFuzzing": false
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit dd1ff8d0996f4549dd916d7fb2abfe959de7dbd0
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Oct 3 13:32:55 2026 +0000

    syz-cluster: applied patch under review

diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h
index 4eeb938f3e61c..6c7e38c993086 100644
--- a/arch/sparc/include/asm/mmu_64.h
+++ b/arch/sparc/include/asm/mmu_64.h
@@ -115,6 +115,11 @@ typedef struct {
 	bool			adi;
 	tag_storage_desc_t	*tag_store;
 	spinlock_t		tag_lock;
+	/* TSB being replaced by tsb_grow(), still used by CPUs that
+	 * have not run tsb_sync() yet.
+	 */
+	struct tsb		*tsb_old[MM_NUM_TSBS];
+	unsigned long		tsb_old_nentries[MM_NUM_TSBS];
 } mm_context_t;
 
 #endif /* !__ASSEMBLER__ */
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 0837ebbc5dce6..16e39f5991ed9 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -971,6 +971,9 @@ struct seq_file;
 void mmu_info(struct seq_file *);
 
 struct vm_area_struct;
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+			  pte_t *ptep, pte_t entry, int dirty);
 void update_mmu_cache_range(struct vm_fault *, struct vm_area_struct *,
 		unsigned long addr, pte_t *ptep, unsigned int nr);
 #define update_mmu_cache(vma, addr, ptep) \
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index 6133306ba59ac..1e2c7e567a2d8 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -48,6 +48,16 @@ void __flush_tlb_all(void);
 void __flush_tlb_page(unsigned long context, unsigned long vaddr);
 void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
+struct vm_area_struct;
+#define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault
+void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
+				  unsigned long address, pte_t *ptep);
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define flush_tlb_fix_spurious_fault_pmd flush_tlb_fix_spurious_fault_pmd
+void flush_tlb_fix_spurious_fault_pmd(struct vm_area_struct *vma,
+				      unsigned long address, pmd_t *pmdp);
+#endif
+
 #ifndef CONFIG_SMP
 
 static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 6d9dd5eb13287..006bee88fee50 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -22,6 +22,41 @@
 
 static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
 
+int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+			  pte_t *ptep, pte_t entry, int dirty)
+{
+	int changed = !pte_same(ptep_get(ptep), entry);
+
+	if (changed)
+		set_pte_at(vma->vm_mm, address, ptep, entry);
+	return changed;
+}
+
+/* Only base pages get here: hugetlb uses huge_ptep_set_access_flags() and
+ * THP the PMD variant below.
+ */
+void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
+				  unsigned long address, pte_t *ptep)
+{
+	address &= PAGE_MASK;
+	flush_tsb_user_page(vma->vm_mm, address, PAGE_SHIFT);
+	global_flush_tlb_page(vma->vm_mm, address);
+}
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+void flush_tlb_fix_spurious_fault_pmd(struct vm_area_struct *vma,
+				      unsigned long address, pmd_t *pmdp)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	address &= HPAGE_MASK;
+	flush_tsb_user_page(mm, address, REAL_HPAGE_SHIFT);
+	flush_tsb_user_page(mm, address + REAL_HPAGE_SIZE, REAL_HPAGE_SHIFT);
+	global_flush_tlb_page(mm, address);
+	global_flush_tlb_page(mm, address + REAL_HPAGE_SIZE);
+}
+#endif
+
 void flush_tlb_pending(void)
 {
 	struct tlb_batch *tb = &get_cpu_var(tlb_batch);
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 5fe52a64c7e70..d73cc1fb05755 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -135,6 +135,20 @@ void flush_tsb_user(struct tlb_batch *tb)
 			__flush_huge_tsb_one(tb, PAGE_SHIFT, base, nentries,
 					     tb->hugepage_shift);
 #endif
+		if (mm->context.tsb_old[MM_TSB_BASE]) {
+			base = (unsigned long) mm->context.tsb_old[MM_TSB_BASE];
+			nentries = mm->context.tsb_old_nentries[MM_TSB_BASE];
+			if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+				base = __pa(base);
+			if (tb->hugepage_shift == PAGE_SHIFT)
+				__flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
+#if defined(CONFIG_HUGETLB_PAGE)
+			else
+				__flush_huge_tsb_one(tb, PAGE_SHIFT, base,
+						     nentries,
+						     tb->hugepage_shift);
+#endif
+		}
 	}
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
 	else if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
@@ -144,6 +158,14 @@ void flush_tsb_user(struct tlb_batch *tb)
 			base = __pa(base);
 		__flush_huge_tsb_one(tb, REAL_HPAGE_SHIFT, base, nentries,
 				     tb->hugepage_shift);
+		if (mm->context.tsb_old[MM_TSB_HUGE]) {
+			base = (unsigned long) mm->context.tsb_old[MM_TSB_HUGE];
+			nentries = mm->context.tsb_old_nentries[MM_TSB_HUGE];
+			if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+				base = __pa(base);
+			__flush_huge_tsb_one(tb, REAL_HPAGE_SHIFT, base,
+					     nentries, tb->hugepage_shift);
+		}
 	}
 #endif
 	spin_unlock_irqrestore(&mm->context.lock, flags);
@@ -169,6 +191,21 @@ void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr,
 			__flush_huge_tsb_one_entry(base, vaddr, PAGE_SHIFT,
 						   nentries, hugepage_shift);
 #endif
+		if (mm->context.tsb_old[MM_TSB_BASE]) {
+			base = (unsigned long) mm->context.tsb_old[MM_TSB_BASE];
+			nentries = mm->context.tsb_old_nentries[MM_TSB_BASE];
+			if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+				base = __pa(base);
+			if (hugepage_shift == PAGE_SHIFT)
+				__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT,
+						      nentries);
+#if defined(CONFIG_HUGETLB_PAGE)
+			else
+				__flush_huge_tsb_one_entry(base, vaddr,
+							   PAGE_SHIFT, nentries,
+							   hugepage_shift);
+#endif
+		}
 	}
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
 	else if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
@@ -178,6 +215,15 @@ void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr,
 			base = __pa(base);
 		__flush_huge_tsb_one_entry(base, vaddr, REAL_HPAGE_SHIFT,
 					   nentries, hugepage_shift);
+		if (mm->context.tsb_old[MM_TSB_HUGE]) {
+			base = (unsigned long) mm->context.tsb_old[MM_TSB_HUGE];
+			nentries = mm->context.tsb_old_nentries[MM_TSB_HUGE];
+			if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+				base = __pa(base);
+			__flush_huge_tsb_one_entry(base, vaddr,
+						   REAL_HPAGE_SHIFT, nentries,
+						   hugepage_shift);
+		}
 	}
 #endif
 	spin_unlock_irqrestore(&mm->context.lock, flags);
@@ -460,17 +506,26 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
 	 * accessing the old TSB via TLB miss handling.  This is OK
 	 * because those actions are just propagating state from the
 	 * Linux page tables into the TSB, page table mappings are not
-	 * being changed.  If a real fault occurs, the processor will
-	 * synchronize with us when it hits flush_tsb_user(), this is
-	 * also true for the case where vmscan is modifying the page
-	 * tables.  The only thing we need to be careful with is to
-	 * skip any locked TSB entries during copy_tsb().
+	 * being changed.  Processors keep using the old TSB until they
+	 * have run tsb_context_switch(), so the old TSB is recorded in
+	 * tsb_old[] and flushed along with the new one until the
+	 * smp_tsb_sync() below has returned.  The only thing we need
+	 * to be careful with is to skip any locked TSB entries during
+	 * copy_tsb().
 	 *
 	 * When we finish committing to the new TSB, we have to drop
 	 * the lock and ask all other cpus running this address space
 	 * to run tsb_context_switch() to see the new TSB table.
+	 *
+	 * An earlier grow of this TSB may still be waiting for the
+	 * other cpus; its old TSB has to stay recorded until then.
 	 */
 	spin_lock_irqsave(&mm->context.lock, flags);
+	while (mm->context.tsb_old[tsb_index]) {
+		spin_unlock_irqrestore(&mm->context.lock, flags);
+		cond_resched();
+		spin_lock_irqsave(&mm->context.lock, flags);
+	}
 
 	old_tsb = mm->context.tsb_block[tsb_index].tsb;
 	old_cache_index =
@@ -511,6 +566,11 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
 			PAGE_SHIFT : REAL_HPAGE_SHIFT);
 	}
 
+	if (old_tsb) {
+		mm->context.tsb_old[tsb_index] = old_tsb;
+		mm->context.tsb_old_nentries[tsb_index] =
+			mm->context.tsb_block[tsb_index].tsb_nentries;
+	}
 	mm->context.tsb_block[tsb_index].tsb = new_tsb;
 	setup_tsb_params(mm, tsb_index, new_size);
 
@@ -529,6 +589,12 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
 		preempt_enable();
 
 		/* Now it is safe to free the old tsb.  */
+		spin_lock_irqsave(&mm->context.lock, flags);
+		if (mm->context.tsb_old[tsb_index] == old_tsb) {
+			mm->context.tsb_old[tsb_index] = NULL;
+			mm->context.tsb_old_nentries[tsb_index] = 0;
+		}
+		spin_unlock_irqrestore(&mm->context.lock, flags);
 		kmem_cache_free(tsb_caches[old_cache_index], old_tsb);
 	}
 }
@@ -566,8 +632,10 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 	 * us, so we need to zero out the TSB pointer or else tsb_grow()
 	 * will be confused and think there is an older TSB to free up.
 	 */
-	for (i = 0; i < MM_NUM_TSBS; i++)
+	for (i = 0; i < MM_NUM_TSBS; i++) {
 		mm->context.tsb_block[i].tsb = NULL;
+		mm->context.tsb_old[i] = NULL;
+	}
 
 	/* If this is fork, inherit the parent's TSB size.  We would
 	 * grow it to that size on the first page fault anyways.

3/2 2026/10/03 13:32 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 6609
							output: 32
							thoughts: 333
						

Thoughts:
**Analyzing a Git Patch: WorthFuzzing Evaluation**

Okay, here's what's running through my head as I review this patch. The user's given me a git patch, and the target architecture for the system is `amd64`. I need to determine if this change is "WorthFuzzing" or not, as per the rules I'm operating under.

First things first: let's get a handle on what's actually been modified. I see the patch affects these files: `arch/sparc/include/asm/mmu_64.h`, `arch/sparc/include/asm/pgtable_64.h`, `arch/sparc/include/asm/tlbflush_64.h`, `arch/sparc/mm/tlb.c`, and `arch/sparc/mm/tsb.c`. Hmm, notice anything? They're ALL under the `arch/sparc/` directory. That's immediately interesting, given the target is amd64.

Now, let's go back to my instructions, specifically section 2, "WHEN TO RETURN WorthFuzzing=false". I'm looking for negative criteria, things that would tell me this isn't worth fuzzing. The key clause I see states: "Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories: ... - Code paths exclusive to architectures other than the target architecture."

Bingo! The patch *only* touches Sparc architecture files (`arch/sparc/*`) and the target architecture is `amd64`. Those files are, by definition, exclusive to a different architecture, not the target architecture. They won't even compile for `amd64`. Therefore, they won't even run on the `amd64` system.

I'm feeling pretty confident, but let's just make sure. Let me use a tool to double check the commit. I want to be 100% certain that *nothing* in this patch is outside of the Sparc architecture, just to be thorough. After the check, I can be certain this is not worth fuzzing.



4/2 2026/10/03 13:33 tool grepper
0m Args:
{
  "Expression": "ptep_set_access_flags",
  "PathPrefix": "arch/sparc"
}

Results:
{
  "Output": "arch/sparc/include/asm/hugetlb.h=33=static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,\n--\narch/sparc/include/asm/hugetlb.h-40-#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS\narch/sparc/include/asm/hugetlb.h:41:static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,\narch/sparc/include/asm/hugetlb.h-42-\t\t\t\t\t     unsigned long addr, pte_t *ptep,\n--\narch/sparc/include/asm/pgtable_32.h=390=static inline unsigned long io_remap_pfn_range_pfn(unsigned long pfn,\n--\narch/sparc/include/asm/pgtable_32.h-403-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS\narch/sparc/include/asm/pgtable_32.h:404:#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \\\narch/sparc/include/asm/pgtable_32.h-405-({\t\t\t\t\t\t\t\t\t  \\\n--\narch/sparc/include/asm/pgtable_64.h=973=struct vm_area_struct;\narch/sparc/include/asm/pgtable_64.h-974-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS\narch/sparc/include/asm/pgtable_64.h:975:int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,\narch/sparc/include/asm/pgtable_64.h-976-\t\t\t  pte_t *ptep, pte_t entry, int dirty);\n--\narch/sparc/mm/tlb.c=23=static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);\narch/sparc/mm/tlb.c-24-\narch/sparc/mm/tlb.c:25:int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,\narch/sparc/mm/tlb.c-26-\t\t\t  pte_t *ptep, pte_t entry, int dirty)\n--\narch/sparc/mm/tlb.c-34-\narch/sparc/mm/tlb.c:35:/* Only base pages get here: hugetlb uses huge_ptep_set_access_flags() and\narch/sparc/mm/tlb.c-36- * THP the PMD variant below.\n"
}

5/2 2026/10/03 13:33 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 8135
							output: 67
							thoughts: 343
						

Thoughts:
**Analysis of the SPARC-Specific Patch**

Okay, so I've just reviewed this diff, and the changes are isolated to a very specific set of files: `arch/sparc/include/asm/mmu_64.h`, `arch/sparc/include/asm/pgtable_64.h`, `arch/sparc/include/asm/tlbflush_64.h`, `arch/sparc/mm/tlb.c`, and `arch/sparc/mm/tsb.c`. The target architecture here is amd64, which is *not* SPARC. Given my understanding of the codebase and the architecture-specific nature of these files, it's immediately clear that these changes are completely unreachable and will never be compiled for the amd64 target.

Now, referring back to section 2 of the guidelines, the criteria for setting `WorthFuzzing` to `false` include "Unreachable execution paths: * Code paths exclusive to architectures other than the target architecture". Bingo. This fits the description perfectly.

Therefore, the verdict is straightforward: `WorthFuzzing` should be `false`. There are no specific configurations I need to enable (`EnableConfigs: []`) and no symbols I need to focus on (`FocusSymbols: []`). The reasoning is simply that the patch exclusively modifies SPARC-specific code that is not relevant to the amd64 architecture. I can succinctly summarize it as: "The patch only modifies SPARC architecture-specific files (arch/sparc/), which are not compiled or executable on the target architecture amd64."

Before I call `set-results`, let's just do a sanity check on the parameters one last time: `EnableConfigs` is empty, `FocusSymbols` is empty, `Reasoning` is concise and accurate, and `WorthFuzzing` is set to false. Perfect. Time to move on.



6/2 2026/10/03 13:33 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "All changes in this patch series are strictly confined to the SPARC architecture (arch/sparc/), making them unreachable and non-compilable on the target amd64 architecture.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "All changes in this patch series are strictly confined to the SPARC architecture (arch/sparc/), making them unreachable and non-compilable on the target amd64 architecture.",
  "WorthFuzzing": false
}

7/1 2026/10/03 13:33 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

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