AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "All modified files are located in arch/riscv/ (RISC-V KVM subsystem). Because the target architecture is amd64, these code paths are exclusive to RISC-V and structurally unreachable on amd64.",
  "WorthFuzzing": false
}

1/1 2026/09/11 16:20 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit dae621878edf772cd85b08ee1effa501348c3c55\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Sep 11 16:20:42 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/arch/riscv/include/asm/kvm_gstage.h b/arch/riscv/include/asm/kvm_gstage.h\nindex aaf080ba1b77a..c61a1bbb272f4 100644\n--- a/arch/riscv/include/asm/kvm_gstage.h\n+++ b/arch/riscv/include/asm/kvm_gstage.h\n@@ -8,7 +8,7 @@\n #define __RISCV_KVM_GSTAGE_H_\n \n #include \u003clinux/kvm_types.h\u003e\n-\n+#include \u003casm/kvm_vmid.h\u003e\n struct kvm_gstage {\n \tstruct kvm *kvm;\n \tunsigned long flags;\n@@ -108,7 +108,8 @@ static inline void kvm_riscv_gstage_init(struct kvm_gstage *gstage, struct kvm *\n {\n \tgstage-\u003ekvm = kvm;\n \tgstage-\u003eflags = 0;\n-\tgstage-\u003evmid = READ_ONCE(kvm-\u003earch.vmid.vmid);\n+\tgstage-\u003evmid =\n+\t\tkvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026kvm-\u003earch.vmid.id));\n \tgstage-\u003epgd = kvm-\u003earch.pgd;\n \tgstage-\u003epgd_levels = kvm-\u003earch.pgd_levels;\n }\ndiff --git a/arch/riscv/include/asm/kvm_mmu.h b/arch/riscv/include/asm/kvm_mmu.h\nindex 5439e76f0a960..aae9b8ac0878f 100644\n--- a/arch/riscv/include/asm/kvm_mmu.h\n+++ b/arch/riscv/include/asm/kvm_mmu.h\n@@ -16,6 +16,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,\n \t\t      struct kvm_gstage_mapping *out_map);\n int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm);\n void kvm_riscv_mmu_free_pgd(struct kvm *kvm);\n+void kvm_riscv_mmu_update_hgatp_vmid(struct kvm_vcpu *vcpu, u64 vmid);\n void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu);\n \n #endif\ndiff --git a/arch/riscv/include/asm/kvm_vmid.h b/arch/riscv/include/asm/kvm_vmid.h\nindex db61b0525a8d0..ddd7cc125c3f6 100644\n--- a/arch/riscv/include/asm/kvm_vmid.h\n+++ b/arch/riscv/include/asm/kvm_vmid.h\n@@ -6,21 +6,42 @@\n #ifndef __RISCV_KVM_VMID_H_\n #define __RISCV_KVM_VMID_H_\n \n+#include \u003clinux/atomic.h\u003e\n #include \u003clinux/kvm_types.h\u003e\n \n struct kvm_vmid {\n \t/*\n-\t * Writes to vmid_version and vmid happen with vmid_lock held\n-\t * whereas reads happen without any lock held.\n+\t * Software VMID:\n+\t *\n+\t *   [ generation | hardware VMID ]\n+\t *\n+\t * Keep the identity 64-bit on RV32 so that the generation does not\n+\t * wrap at the native word size.  Zero denotes an unallocated VMID.\n+\t *\n+\t * Only the low hardware VMID bits may be written to HGATP\n+\t * or used as a hardware fence VMID.\n \t */\n-\tunsigned long vmid_version;\n-\tunsigned long vmid;\n+\tatomic64_t id;\n };\n \n void __init kvm_riscv_gstage_vmid_detect(void);\n unsigned long kvm_riscv_gstage_vmid_bits(void);\n+\n+int __init kvm_riscv_gstage_vmid_alloc_init(void);\n+void kvm_riscv_gstage_vmid_alloc_free(void);\n+\n int kvm_riscv_gstage_vmid_init(struct kvm *kvm);\n+\n+unsigned long kvm_riscv_gstage_vmid_hwid(u64 vmid);\n+\n bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid);\n+\n void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu);\n \n+/*\n+ * Invalidate the current CPU's fast-path VMID state while preserving\n+ * the old identity conservatively in reserved_vmids.\n+ */\n+void kvm_riscv_gstage_vmid_cpu_invalidate(void);\n+\n #endif\ndiff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c\nindex 89568ccce01de..d6c6be4df61b1 100644\n--- a/arch/riscv/kvm/main.c\n+++ b/arch/riscv/kvm/main.c\n@@ -16,7 +16,7 @@\n #include \u003casm/kvm_nacl.h\u003e\n #include \u003casm/sbi.h\u003e\n #include \u003casm/kvm_vcpu_vector.h\u003e\n-\n+#include \u003casm/kvm_vmid.h\u003e\n static DEFINE_PER_CPU(bool, kvm_riscv_virtualization_enabled);\n \n DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);\n@@ -84,6 +84,7 @@ int kvm_arch_enable_virtualization_cpu(void)\n \n void kvm_arch_disable_virtualization_cpu(void)\n {\n+\tkvm_riscv_gstage_vmid_cpu_invalidate();\n \tkvm_riscv_aia_disable();\n \tkvm_riscv_csr_cleanup();\n \tkvm_riscv_nacl_disable();\n@@ -112,6 +113,7 @@ static int kvm_riscv_cpu_pm_notifier(struct notifier_block *self, unsigned long\n \t\t * is enabled on this CPU.\n \t\t */\n \t\tif (__this_cpu_read(kvm_riscv_virtualization_enabled)) {\n+\t\t\tkvm_riscv_gstage_vmid_cpu_invalidate();\n \t\t\tkvm_riscv_aia_pm_enter();\n \t\t\tkvm_riscv_csr_cleanup();\n \t\t}\n@@ -130,6 +132,7 @@ static struct notifier_block kvm_riscv_cpu_pm_nb = {\n static void kvm_riscv_teardown(void)\n {\n \tkvm_riscv_aia_exit();\n+\tkvm_riscv_gstage_vmid_alloc_free();\n \tkvm_riscv_nacl_exit();\n \tkvm_riscv_v_exit();\n \tkvm_unregister_perf_callbacks();\n@@ -181,8 +184,15 @@ static int __init riscv_kvm_init(void)\n \n \tkvm_riscv_gstage_vmid_detect();\n \n+\trc = kvm_riscv_gstage_vmid_alloc_init();\n+\tif (rc) {\n+\t\tkvm_riscv_nacl_exit();\n+\t\treturn rc;\n+\t}\n+\n \trc = kvm_riscv_aia_init();\n \tif (rc \u0026\u0026 rc != -ENODEV) {\n+\t\tkvm_riscv_gstage_vmid_alloc_free();\n \t\tkvm_riscv_nacl_exit();\n \t\treturn rc;\n \t}\ndiff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c\nindex 6035b5ec95039..9b597092f8ec6 100644\n--- a/arch/riscv/kvm/mmu.c\n+++ b/arch/riscv/kvm/mmu.c\n@@ -15,7 +15,7 @@\n #include \u003clinux/sched/signal.h\u003e\n #include \u003casm/kvm_mmu.h\u003e\n #include \u003casm/kvm_nacl.h\u003e\n-\n+#include \u003casm/kvm_vmid.h\u003e\n static bool __read_mostly eager_page_split = true;\n module_param(eager_page_split, bool, 0644);\n \n@@ -796,16 +796,23 @@ void kvm_riscv_mmu_free_pgd(struct kvm *kvm)\n \tkvm_mmu_free_memory_cache(\u0026kvm-\u003earch.pgd_split_page_cache);\n }\n \n-void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)\n+void kvm_riscv_mmu_update_hgatp_vmid(struct kvm_vcpu *vcpu, u64 vmid)\n {\n \tstruct kvm_arch *ka = \u0026vcpu-\u003ekvm-\u003earch;\n \tunsigned long hgatp = kvm_riscv_gstage_mode(ka-\u003epgd_levels)\n \t\t\t      \u003c\u003c HGATP_MODE_SHIFT;\n \n-\thgatp |= (READ_ONCE(ka-\u003evmid.vmid) \u003c\u003c HGATP_VMID_SHIFT) \u0026 HGATP_VMID;\n+\thgatp |= (kvm_riscv_gstage_vmid_hwid(vmid) \u003c\u003c HGATP_VMID_SHIFT) \u0026 HGATP_VMID;\n \thgatp |= (ka-\u003epgd_phys \u003e\u003e PAGE_SHIFT) \u0026 HGATP_PPN;\n \n \tncsr_write(CSR_HGATP, hgatp);\n+}\n+\n+void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)\n+{\n+\tu64 vmid = atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id);\n+\n+\tkvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);\n \n \tif (!kvm_riscv_gstage_vmid_bits())\n \t\tkvm_riscv_local_hfence_gvma_all();\ndiff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c\nindex 2ae34632cdcb1..b85e5ba2198aa 100644\n--- a/arch/riscv/kvm/tlb.c\n+++ b/arch/riscv/kvm/tlb.c\n@@ -224,7 +224,7 @@ void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)\n \t * entries by VMID whenever underlying Host CPU changes for a VCPU.\n \t */\n \n-\tvmid = READ_ONCE(vcpu-\u003ekvm-\u003earch.vmid.vmid);\n+\tvmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id));\n \tkvm_riscv_local_hfence_gvma_vmid_all(vmid);\n \n \t/*\n@@ -244,7 +244,7 @@ void kvm_riscv_fence_i_process(struct kvm_vcpu *vcpu)\n void kvm_riscv_tlb_flush_process(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vmid *v = \u0026vcpu-\u003ekvm-\u003earch.vmid;\n-\tunsigned long vmid = READ_ONCE(v-\u003evmid);\n+\tunsigned long vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026v-\u003eid));\n \n \tif (kvm_riscv_nacl_available())\n \t\tnacl_hfence_gvma_vmid_all(nacl_shmem(), vmid);\n@@ -255,7 +255,7 @@ void kvm_riscv_tlb_flush_process(struct kvm_vcpu *vcpu)\n void kvm_riscv_hfence_vvma_all_process(struct kvm_vcpu *vcpu)\n {\n \tstruct kvm_vmid *v = \u0026vcpu-\u003ekvm-\u003earch.vmid;\n-\tunsigned long vmid = READ_ONCE(v-\u003evmid);\n+\tunsigned long vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026v-\u003eid));\n \n \tif (kvm_riscv_nacl_available())\n \t\tnacl_hfence_vvma_all(nacl_shmem(), vmid);\n@@ -531,8 +531,11 @@ void kvm_riscv_hfence_vvma_all(struct kvm *kvm,\n \n int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages)\n {\n+\tunsigned long vmid =\n+\t\tkvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026kvm-\u003earch.vmid.id));\n+\n \tkvm_riscv_hfence_gvma_vmid_gpa(kvm, -1UL, 0,\n \t\t\t\t       gfn \u003c\u003c PAGE_SHIFT, nr_pages \u003c\u003c PAGE_SHIFT,\n-\t\t\t\t       PAGE_SHIFT, READ_ONCE(kvm-\u003earch.vmid.vmid));\n+\t\t\t\t       PAGE_SHIFT, vmid);\n \treturn 0;\n }\ndiff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c\nindex e062ca19f9d8f..85542c1a5ec3f 100644\n--- a/arch/riscv/kvm/vcpu.c\n+++ b/arch/riscv/kvm/vcpu.c\n@@ -943,14 +943,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)\n \t\t\tcontinue;\n \t\tret = 1;\n \n-\t\tkvm_riscv_gstage_vmid_update(vcpu);\n-\n \t\tret = kvm_riscv_check_vcpu_requests(vcpu);\n \t\tif (ret \u003c= 0)\n \t\t\tcontinue;\n \n \t\tpreempt_disable();\n \n+\t\tkvm_riscv_gstage_vmid_update(vcpu);\n+\n \t\t/* Update AIA HW state before entering guest */\n \t\tret = kvm_riscv_vcpu_aia_update(vcpu);\n \t\tif (ret \u003c= 0) {\ndiff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c\nindex 506a510b6bff3..1be386a78e27f 100644\n--- a/arch/riscv/kvm/vcpu_sbi_replace.c\n+++ b/arch/riscv/kvm/vcpu_sbi_replace.c\n@@ -104,7 +104,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run\n \t\tkvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_FENCE_I_SENT);\n \t\tbreak;\n \tcase SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:\n-\t\tvmid = READ_ONCE(vcpu-\u003ekvm-\u003earch.vmid.vmid);\n+\t\tvmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id));\n \t\tif ((cp-\u003ea2 == 0 \u0026\u0026 cp-\u003ea3 == 0) || cp-\u003ea3 == -1UL)\n \t\t\tkvm_riscv_hfence_vvma_all(vcpu-\u003ekvm, hbase, hmask, vmid);\n \t\telse\n@@ -113,7 +113,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run\n \t\tkvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_SENT);\n \t\tbreak;\n \tcase SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:\n-\t\tvmid = READ_ONCE(vcpu-\u003ekvm-\u003earch.vmid.vmid);\n+\t\tvmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id));\n \t\tif ((cp-\u003ea2 == 0 \u0026\u0026 cp-\u003ea3 == 0) || cp-\u003ea3 == -1UL)\n \t\t\tkvm_riscv_hfence_vvma_asid_all(vcpu-\u003ekvm, hbase, hmask,\n \t\t\t\t\t\t       cp-\u003ea4, vmid);\ndiff --git a/arch/riscv/kvm/vcpu_sbi_v01.c b/arch/riscv/kvm/vcpu_sbi_v01.c\nindex de544ea3f28dc..ca3efe63c1cf1 100644\n--- a/arch/riscv/kvm/vcpu_sbi_v01.c\n+++ b/arch/riscv/kvm/vcpu_sbi_v01.c\n@@ -88,14 +88,14 @@ static int kvm_sbi_ext_v01_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,\n \t\tif (cp-\u003ea7 == SBI_EXT_0_1_REMOTE_FENCE_I)\n \t\t\tkvm_riscv_fence_i(vcpu-\u003ekvm, hbase, hmask);\n \t\telse if (cp-\u003ea7 == SBI_EXT_0_1_REMOTE_SFENCE_VMA) {\n-\t\t\tvmid = READ_ONCE(vcpu-\u003ekvm-\u003earch.vmid.vmid);\n+\t\t\tvmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id));\n \t\t\tif (cp-\u003ea1 == 0 \u0026\u0026 cp-\u003ea2 == 0)\n \t\t\t\tkvm_riscv_hfence_vvma_all(vcpu-\u003ekvm, hbase, hmask, vmid);\n \t\t\telse\n \t\t\t\tkvm_riscv_hfence_vvma_gva(vcpu-\u003ekvm, hbase, hmask, cp-\u003ea1,\n \t\t\t\t\t\t\t  cp-\u003ea2, PAGE_SHIFT, vmid);\n \t\t} else {\n-\t\t\tvmid = READ_ONCE(vcpu-\u003ekvm-\u003earch.vmid.vmid);\n+\t\t\tvmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(\u0026vcpu-\u003ekvm-\u003earch.vmid.id));\n \t\t\tif (cp-\u003ea1 == 0 \u0026\u0026 cp-\u003ea2 == 0)\n \t\t\t\tkvm_riscv_hfence_vvma_asid_all(vcpu-\u003ekvm, hbase, hmask,\n \t\t\t\t\t\t\t       cp-\u003ea3, vmid);\ndiff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c\nindex c15bdb1dd8bef..eee8306c12707 100644\n--- a/arch/riscv/kvm/vmid.c\n+++ b/arch/riscv/kvm/vmid.c\n@@ -6,11 +6,15 @@\n  *     Anup Patel \u003canup.patel@wdc.com\u003e\n  */\n \n+#include \u003clinux/bitmap.h\u003e\n #include \u003clinux/bitops.h\u003e\n #include \u003clinux/cpumask.h\u003e\n #include \u003clinux/errno.h\u003e\n #include \u003clinux/err.h\u003e\n #include \u003clinux/module.h\u003e\n+#include \u003clinux/percpu.h\u003e\n+#include \u003clinux/preempt.h\u003e\n+#include \u003clinux/slab.h\u003e\n #include \u003clinux/smp.h\u003e\n #include \u003clinux/kvm_host.h\u003e\n #include \u003casm/csr.h\u003e\n@@ -18,26 +22,54 @@\n #include \u003casm/kvm_tlb.h\u003e\n #include \u003casm/kvm_vmid.h\u003e\n \n-static unsigned long vmid_version = 1;\n-static unsigned long vmid_next;\n+static atomic64_t vmid_generation;\n+static unsigned long *vmid_map;\n static unsigned long vmid_bits __ro_after_init;\n-static DEFINE_SPINLOCK(vmid_lock);\n+static unsigned long vmid_cur_idx = 1;\n+\n+static DEFINE_RAW_SPINLOCK(vmid_lock);\n+\n+static DEFINE_PER_CPU(atomic64_t, active_vmids);\n+static DEFINE_PER_CPU(u64, reserved_vmids);\n+\n+static cpumask_t tlb_flush_pending;\n+\n+#define VMID_FIRST_VERSION\tBIT_ULL(vmid_bits)\n+#define NUM_VMIDS\t\tBIT(vmid_bits)\n+#define VMID_HW_MASK\t\t(VMID_FIRST_VERSION - 1)\n+\n+static bool vmid_gen_match(u64 vmid)\n+{\n+\treturn !((vmid ^ atomic64_read(\u0026vmid_generation)) \u003e\u003e vmid_bits);\n+}\n+\n+unsigned long kvm_riscv_gstage_vmid_hwid(u64 vmid)\n+{\n+\tif (!vmid_bits)\n+\t\treturn 0;\n+\n+\treturn (unsigned long)(vmid \u0026 VMID_HW_MASK);\n+}\n \n void __init kvm_riscv_gstage_vmid_detect(void)\n {\n-\t/* Figure-out number of VMID bits in HW */\n+\t/* Figure out the number of VMID bits supported by hardware. */\n \tcsr_write(CSR_HGATP, (kvm_riscv_gstage_mode(kvm_riscv_gstage_max_pgd_levels) \u003c\u003c\n-\t\t\t      HGATP_MODE_SHIFT) | HGATP_VMID);\n+\t\t   HGATP_MODE_SHIFT) | HGATP_VMID);\n \tvmid_bits = csr_read(CSR_HGATP);\n \tvmid_bits = (vmid_bits \u0026 HGATP_VMID) \u003e\u003e HGATP_VMID_SHIFT;\n \tvmid_bits = fls_long(vmid_bits);\n \tcsr_write(CSR_HGATP, 0);\n \n-\t/* We polluted local TLB so flush all guest TLB */\n+\t/* Flush the local guest TLB after probing HGATP. */\n \tkvm_riscv_local_hfence_gvma_all();\n \n-\t/* We don't use VMID bits if they are not sufficient */\n-\tif ((1UL \u003c\u003c vmid_bits) \u003c num_possible_cpus())\n+\t/*\n+\t * VMID 0 is reserved.  During rollover every possible CPU may\n+\t * reserve one hardware VMID, and we still need at least one VMID\n+\t * available for a new allocation.\n+\t */\n+\tif (vmid_bits \u0026\u0026 NUM_VMIDS - 1 \u003c= num_possible_cpus())\n \t\tvmid_bits = 0;\n }\n \n@@ -46,80 +78,295 @@ unsigned long kvm_riscv_gstage_vmid_bits(void)\n \treturn vmid_bits;\n }\n \n+int __init kvm_riscv_gstage_vmid_alloc_init(void)\n+{\n+\tint cpu;\n+\n+\tif (!vmid_bits)\n+\t\treturn 0;\n+\n+\tvmid_map = bitmap_zalloc(NUM_VMIDS, GFP_KERNEL);\n+\tif (!vmid_map)\n+\t\treturn -ENOMEM;\n+\n+\tvmid_cur_idx = 1;\n+\n+\t/* Hardware VMID 0 is reserved. */\n+\t__set_bit(0, vmid_map);\n+\n+\tatomic64_set(\u0026vmid_generation, VMID_FIRST_VERSION);\n+\n+\tfor_each_possible_cpu(cpu) {\n+\t\tatomic64_set(\u0026per_cpu(active_vmids, cpu), 0);\n+\t\tper_cpu(reserved_vmids, cpu) = 0;\n+\t}\n+\n+\t/*\n+\t * Every CPU performs an initial local invalidation before its\n+\t * first VMID activation.\n+\t */\n+\tcpumask_copy(\u0026tlb_flush_pending, cpu_possible_mask);\n+\n+\treturn 0;\n+}\n+\n+void kvm_riscv_gstage_vmid_alloc_free(void)\n+{\n+\tbitmap_free(vmid_map);\n+\tvmid_map = NULL;\n+}\n+\n int kvm_riscv_gstage_vmid_init(struct kvm *kvm)\n {\n-\t/* Mark the initial VMID and VMID version invalid */\n-\tkvm-\u003earch.vmid.vmid_version = 0;\n-\tkvm-\u003earch.vmid.vmid = 0;\n+\tatomic64_set(\u0026kvm-\u003earch.vmid.id, 0);\n \n \treturn 0;\n }\n \n bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid)\n {\n+\tu64 id;\n+\n \tif (!vmid_bits)\n \t\treturn false;\n \n-\treturn unlikely(READ_ONCE(vmid-\u003evmid_version) !=\n-\t\t\tREAD_ONCE(vmid_version));\n+\tid = atomic64_read(\u0026vmid-\u003eid);\n+\n+\treturn unlikely(!vmid_gen_match(id));\n }\n \n-static void __local_hfence_gvma_all(void *info)\n+/*\n+ * Called with vmid_lock held after vmid_generation has already been\n+ * advanced.\n+ *\n+ * No remote CPU is interrupted here.  Instead, preserve every VMID\n+ * which may still be used by a CPU and queue a local invalidation for\n+ * that CPU's next VMID activation.\n+ */\n+static void flush_context(void)\n {\n-\tkvm_riscv_local_hfence_gvma_all();\n+\tu64 vmid;\n+\tint cpu;\n+\n+\tbitmap_zero(vmid_map, NUM_VMIDS);\n+\t__set_bit(0, vmid_map);\n+\n+\tfor_each_possible_cpu(cpu) {\n+\t\tvmid = atomic64_xchg(\u0026per_cpu(active_vmids, cpu), 0);\n+\n+\t\t/*\n+\t\t * The CPU may already have been caught by an earlier rollover\n+\t\t * without performing another activation since then.  In that\n+\t\t * case reserved_vmids is the only record of the old context.\n+\t\t */\n+\t\tif (!vmid)\n+\t\t\tvmid = per_cpu(reserved_vmids, cpu);\n+\n+\t\tif (vmid)\n+\t\t\t__set_bit(kvm_riscv_gstage_vmid_hwid(vmid),\n+\t\t\t\t  vmid_map);\n+\n+\t\tper_cpu(reserved_vmids, cpu) = vmid;\n+\t}\n+\n+\tcpumask_copy(\u0026tlb_flush_pending, cpu_possible_mask);\n }\n \n-void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)\n+/*\n+ * Update every reserved copy of an old software VMID.\n+ *\n+ * Do not stop after the first match: the same VM may have been active\n+ * on more than one CPU when rollover occurred.\n+ */\n+static bool check_update_reserved_vmid(u64 old_vmid, u64 new_vmid)\n {\n-\tunsigned long i;\n-\tstruct kvm_vcpu *v;\n-\tstruct kvm_vmid *vmid = \u0026vcpu-\u003ekvm-\u003earch.vmid;\n+\tbool hit = false;\n+\tint cpu;\n \n-\tif (!kvm_riscv_gstage_vmid_ver_changed(vmid))\n-\t\treturn;\n+\tfor_each_possible_cpu(cpu) {\n+\t\tif (per_cpu(reserved_vmids, cpu) == old_vmid) {\n+\t\t\tper_cpu(reserved_vmids, cpu) = new_vmid;\n+\t\t\thit = true;\n+\t\t}\n+\t}\n+\n+\treturn hit;\n+}\n+\n+/*\n+ * Allocate/promote a software VMID.\n+ *\n+ * vmid_lock must be held by the caller.\n+ */\n+static u64 new_vmid_locked(struct kvm_vmid *kvm_vmid)\n+{\n+\tu64 vmid = atomic64_read(\u0026kvm_vmid-\u003eid);\n+\tu64 generation = atomic64_read(\u0026vmid_generation);\n+\tu64 new_vmid;\n+\tunsigned long idx;\n \n-\tspin_lock(\u0026vmid_lock);\n+\tif (vmid) {\n+\t\tnew_vmid = generation |\n+\t\t\t   kvm_riscv_gstage_vmid_hwid(vmid);\n+\n+\t\t/*\n+\t\t * The old VMID is still protected by one or more CPUs.\n+\t\t * Keep the same hardware VMID and only promote generation.\n+\t\t */\n+\t\tif (check_update_reserved_vmid(vmid, new_vmid))\n+\t\t\treturn new_vmid;\n+\n+\t\t/*\n+\t\t * The VM had a VMID in an older generation.  Reuse the same\n+\t\t * hardware number if it has not already been claimed.\n+\t\t */\n+\t\tidx = kvm_riscv_gstage_vmid_hwid(vmid);\n+\t\tif (!__test_and_set_bit(idx, vmid_map))\n+\t\t\treturn new_vmid;\n+\t}\n+\n+\t/*\n+\t * Find a free VMID in the current generation.\n+\t */\n+\tidx = find_next_zero_bit(vmid_map, NUM_VMIDS, vmid_cur_idx);\n+\tif (idx != NUM_VMIDS)\n+\t\tgoto set_vmid;\n+\n+\t/*\n+\t * No free VMID.  Start a new generation, preserve all CPU-local\n+\t * users, and defer each CPU's flush until its next activation.\n+\t */\n+\tgeneration += VMID_FIRST_VERSION;\n+\n+\t/* Software VMID 0 is reserved as the invalid identifier. */\n+\tif (unlikely(!generation))\n+\t\tgeneration = VMID_FIRST_VERSION;\n+\n+\tatomic64_xchg(\u0026vmid_generation, generation);\n+\tflush_context();\n \n \t/*\n-\t * We need to re-check the vmid_version here to ensure that if\n-\t * another vcpu already allocated a valid vmid for this vm.\n+\t * NUM_VMIDS - 1 \u003e num_possible_cpus(), therefore rollover must\n+\t * leave at least one allocatable hardware VMID.\n \t */\n-\tif (!kvm_riscv_gstage_vmid_ver_changed(vmid)) {\n-\t\tspin_unlock(\u0026vmid_lock);\n+\tidx = find_next_zero_bit(vmid_map, NUM_VMIDS, 1);\n+\n+set_vmid:\n+\t__set_bit(idx, vmid_map);\n+\tvmid_cur_idx = idx;\n+\n+\treturn generation | idx;\n+}\n+\n+void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm_vmid *kvm_vmid = \u0026vcpu-\u003ekvm-\u003earch.vmid;\n+\tatomic64_t *active;\n+\tunsigned long flags;\n+\tu64 vmid;\n+\tu64 old_active_vmid;\n+\tunsigned int cpu;\n+\n+\tif (!vmid_bits)\n \t\treturn;\n-\t}\n \n-\t/* First user of a new VMID version? */\n-\tif (unlikely(vmid_next == 0)) {\n-\t\tWRITE_ONCE(vmid_version, READ_ONCE(vmid_version) + 1);\n-\t\tvmid_next = 1;\n+\t/*\n+\t * active_vmids and tlb_flush_pending are per-CPU state.  Keep the\n+\t * complete VMID activation on the same CPU.\n+\t */\n+\tlockdep_assert_preemption_disabled();\n+\n+\tcpu = smp_processor_id();\n+\tactive = this_cpu_ptr(\u0026active_vmids);\n+\n+\tvmid = atomic64_read(\u0026kvm_vmid-\u003eid);\n+\told_active_vmid = atomic64_read(active);\n \n+\t/*\n+\t * Fast path.\n+\t *\n+\t * The cmpxchg races with flush_context()'s xchg on the same\n+\t * per-CPU atomic.  Either this activation is captured by rollover,\n+\t * or rollover clears active first and the cmpxchg fails.\n+\t */\n+\tif (old_active_vmid \u0026\u0026 vmid_gen_match(vmid)) {\n \t\t/*\n-\t\t * We ran out of VMIDs so we increment vmid_version and\n-\t\t * start assigning VMIDs from 1.\n-\t\t *\n-\t\t * This also means existing VMIDs assignment to all Guest\n-\t\t * instances is invalid and we have force VMID re-assignement\n-\t\t * for all Guest instances. The Guest instances that were not\n-\t\t * running will automatically pick-up new VMIDs because will\n-\t\t * call kvm_riscv_gstage_vmid_update() whenever they enter\n-\t\t * in-kernel run loop. For Guest instances that are already\n-\t\t * running, we force VM exits on all host CPUs using IPI and\n-\t\t * flush all Guest TLBs.\n+\t\t * HGATP must contain the same hardware VMID that is published\n+\t\t * in active_vmids.\n \t\t */\n-\t\ton_each_cpu_mask(cpu_online_mask, __local_hfence_gvma_all,\n-\t\t\t\t NULL, 1);\n+\t\tif (old_active_vmid != vmid)\n+\t\t\tkvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);\n+\n+\t\tif (atomic64_cmpxchg(active, old_active_vmid, vmid) ==\n+\t\t    old_active_vmid)\n+\t\t\treturn;\n \t}\n \n-\tvmid-\u003evmid = vmid_next;\n-\tvmid_next++;\n-\tvmid_next \u0026= (1 \u003c\u003c vmid_bits) - 1;\n+\traw_spin_lock_irqsave(\u0026vmid_lock, flags);\n \n-\tWRITE_ONCE(vmid-\u003evmid_version, READ_ONCE(vmid_version));\n+\t/*\n+\t * Re-read under the allocator lock because another vCPU of this VM\n+\t * may already have promoted or allocated the shared VMID.\n+\t */\n+\tvmid = atomic64_read(\u0026kvm_vmid-\u003eid);\n+\n+\tif (!vmid_gen_match(vmid)) {\n+\t\tvmid = new_vmid_locked(kvm_vmid);\n+\t\tatomic64_set(\u0026kvm_vmid-\u003eid, vmid);\n+\t}\n+\n+\t/*\n+\t * Complete this CPU's deferred rollover invalidation before\n+\t * installing the new hardware VMID.\n+\t */\n+\tif (cpumask_test_and_clear_cpu(cpu, \u0026tlb_flush_pending))\n+\t\tkvm_riscv_local_hfence_gvma_all();\n+\n+\t/*\n+\t * Install the current hardware VMID before publishing this CPU as\n+\t * active with the new software VMID.\n+\t */\n+\tkvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);\n+\n+\t/*\n+\t * Once active_vmids is visible, the required local invalidation and\n+\t * HGATP update are complete.\n+\t */\n+\tatomic64_set(active, vmid);\n+\n+\traw_spin_unlock_irqrestore(\u0026vmid_lock, flags);\n+}\n \n-\tspin_unlock(\u0026vmid_lock);\n+/*\n+ * CPU virtualization/CSR state is being discarded.\n+ *\n+ * Withdraw fast-path eligibility, but conservatively preserve the last\n+ * identity instead of making its hardware VMID immediately reusable.\n+ */\n+void kvm_riscv_gstage_vmid_cpu_invalidate(void)\n+{\n+\tunsigned long flags;\n+\tu64 vmid;\n+\tunsigned int cpu;\n+\n+\tif (!vmid_bits)\n+\t\treturn;\n+\n+\tlockdep_assert_preemption_disabled();\n+\n+\tcpu = smp_processor_id();\n+\n+\traw_spin_lock_irqsave(\u0026vmid_lock, flags);\n+\n+\tvmid = atomic64_xchg(this_cpu_ptr(\u0026active_vmids), 0);\n+\n+\tif (vmid)\n+\t\tper_cpu(reserved_vmids, cpu) = vmid;\n+\n+\t/*\n+\t * If active was already zero, retain the old reserved entry.\n+\t */\n+\tcpumask_set_cpu(cpu, \u0026tlb_flush_pending);\n \n-\t/* Request G-stage page table update for all VCPUs */\n-\tkvm_for_each_vcpu(i, v, vcpu-\u003ekvm)\n-\t\tkvm_make_request(KVM_REQ_UPDATE_HGATP, v);\n+\traw_spin_unlock_irqrestore(\u0026vmid_lock, flags);\n }\n"
}

2/1 2026/09/11 16:20 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "All modified files are located in arch/riscv/ (RISC-V KVM subsystem). Because the target architecture is amd64, these code paths are exclusive to RISC-V and structurally unreachable on amd64.",
  "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 dae621878edf772cd85b08ee1effa501348c3c55
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Sep 11 16:20:42 2026 +0000

    syz-cluster: applied patch under review

diff --git a/arch/riscv/include/asm/kvm_gstage.h b/arch/riscv/include/asm/kvm_gstage.h
index aaf080ba1b77a..c61a1bbb272f4 100644
--- a/arch/riscv/include/asm/kvm_gstage.h
+++ b/arch/riscv/include/asm/kvm_gstage.h
@@ -8,7 +8,7 @@
 #define __RISCV_KVM_GSTAGE_H_
 
 #include <linux/kvm_types.h>
-
+#include <asm/kvm_vmid.h>
 struct kvm_gstage {
 	struct kvm *kvm;
 	unsigned long flags;
@@ -108,7 +108,8 @@ static inline void kvm_riscv_gstage_init(struct kvm_gstage *gstage, struct kvm *
 {
 	gstage->kvm = kvm;
 	gstage->flags = 0;
-	gstage->vmid = READ_ONCE(kvm->arch.vmid.vmid);
+	gstage->vmid =
+		kvm_riscv_gstage_vmid_hwid(atomic64_read(&kvm->arch.vmid.id));
 	gstage->pgd = kvm->arch.pgd;
 	gstage->pgd_levels = kvm->arch.pgd_levels;
 }
diff --git a/arch/riscv/include/asm/kvm_mmu.h b/arch/riscv/include/asm/kvm_mmu.h
index 5439e76f0a960..aae9b8ac0878f 100644
--- a/arch/riscv/include/asm/kvm_mmu.h
+++ b/arch/riscv/include/asm/kvm_mmu.h
@@ -16,6 +16,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 		      struct kvm_gstage_mapping *out_map);
 int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm);
 void kvm_riscv_mmu_free_pgd(struct kvm *kvm);
+void kvm_riscv_mmu_update_hgatp_vmid(struct kvm_vcpu *vcpu, u64 vmid);
 void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu);
 
 #endif
diff --git a/arch/riscv/include/asm/kvm_vmid.h b/arch/riscv/include/asm/kvm_vmid.h
index db61b0525a8d0..ddd7cc125c3f6 100644
--- a/arch/riscv/include/asm/kvm_vmid.h
+++ b/arch/riscv/include/asm/kvm_vmid.h
@@ -6,21 +6,42 @@
 #ifndef __RISCV_KVM_VMID_H_
 #define __RISCV_KVM_VMID_H_
 
+#include <linux/atomic.h>
 #include <linux/kvm_types.h>
 
 struct kvm_vmid {
 	/*
-	 * Writes to vmid_version and vmid happen with vmid_lock held
-	 * whereas reads happen without any lock held.
+	 * Software VMID:
+	 *
+	 *   [ generation | hardware VMID ]
+	 *
+	 * Keep the identity 64-bit on RV32 so that the generation does not
+	 * wrap at the native word size.  Zero denotes an unallocated VMID.
+	 *
+	 * Only the low hardware VMID bits may be written to HGATP
+	 * or used as a hardware fence VMID.
 	 */
-	unsigned long vmid_version;
-	unsigned long vmid;
+	atomic64_t id;
 };
 
 void __init kvm_riscv_gstage_vmid_detect(void);
 unsigned long kvm_riscv_gstage_vmid_bits(void);
+
+int __init kvm_riscv_gstage_vmid_alloc_init(void);
+void kvm_riscv_gstage_vmid_alloc_free(void);
+
 int kvm_riscv_gstage_vmid_init(struct kvm *kvm);
+
+unsigned long kvm_riscv_gstage_vmid_hwid(u64 vmid);
+
 bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid);
+
 void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu);
 
+/*
+ * Invalidate the current CPU's fast-path VMID state while preserving
+ * the old identity conservatively in reserved_vmids.
+ */
+void kvm_riscv_gstage_vmid_cpu_invalidate(void);
+
 #endif
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index 89568ccce01de..d6c6be4df61b1 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -16,7 +16,7 @@
 #include <asm/kvm_nacl.h>
 #include <asm/sbi.h>
 #include <asm/kvm_vcpu_vector.h>
-
+#include <asm/kvm_vmid.h>
 static DEFINE_PER_CPU(bool, kvm_riscv_virtualization_enabled);
 
 DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
@@ -84,6 +84,7 @@ int kvm_arch_enable_virtualization_cpu(void)
 
 void kvm_arch_disable_virtualization_cpu(void)
 {
+	kvm_riscv_gstage_vmid_cpu_invalidate();
 	kvm_riscv_aia_disable();
 	kvm_riscv_csr_cleanup();
 	kvm_riscv_nacl_disable();
@@ -112,6 +113,7 @@ static int kvm_riscv_cpu_pm_notifier(struct notifier_block *self, unsigned long
 		 * is enabled on this CPU.
 		 */
 		if (__this_cpu_read(kvm_riscv_virtualization_enabled)) {
+			kvm_riscv_gstage_vmid_cpu_invalidate();
 			kvm_riscv_aia_pm_enter();
 			kvm_riscv_csr_cleanup();
 		}
@@ -130,6 +132,7 @@ static struct notifier_block kvm_riscv_cpu_pm_nb = {
 static void kvm_riscv_teardown(void)
 {
 	kvm_riscv_aia_exit();
+	kvm_riscv_gstage_vmid_alloc_free();
 	kvm_riscv_nacl_exit();
 	kvm_riscv_v_exit();
 	kvm_unregister_perf_callbacks();
@@ -181,8 +184,15 @@ static int __init riscv_kvm_init(void)
 
 	kvm_riscv_gstage_vmid_detect();
 
+	rc = kvm_riscv_gstage_vmid_alloc_init();
+	if (rc) {
+		kvm_riscv_nacl_exit();
+		return rc;
+	}
+
 	rc = kvm_riscv_aia_init();
 	if (rc && rc != -ENODEV) {
+		kvm_riscv_gstage_vmid_alloc_free();
 		kvm_riscv_nacl_exit();
 		return rc;
 	}
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 6035b5ec95039..9b597092f8ec6 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -15,7 +15,7 @@
 #include <linux/sched/signal.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nacl.h>
-
+#include <asm/kvm_vmid.h>
 static bool __read_mostly eager_page_split = true;
 module_param(eager_page_split, bool, 0644);
 
@@ -796,16 +796,23 @@ void kvm_riscv_mmu_free_pgd(struct kvm *kvm)
 	kvm_mmu_free_memory_cache(&kvm->arch.pgd_split_page_cache);
 }
 
-void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)
+void kvm_riscv_mmu_update_hgatp_vmid(struct kvm_vcpu *vcpu, u64 vmid)
 {
 	struct kvm_arch *ka = &vcpu->kvm->arch;
 	unsigned long hgatp = kvm_riscv_gstage_mode(ka->pgd_levels)
 			      << HGATP_MODE_SHIFT;
 
-	hgatp |= (READ_ONCE(ka->vmid.vmid) << HGATP_VMID_SHIFT) & HGATP_VMID;
+	hgatp |= (kvm_riscv_gstage_vmid_hwid(vmid) << HGATP_VMID_SHIFT) & HGATP_VMID;
 	hgatp |= (ka->pgd_phys >> PAGE_SHIFT) & HGATP_PPN;
 
 	ncsr_write(CSR_HGATP, hgatp);
+}
+
+void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)
+{
+	u64 vmid = atomic64_read(&vcpu->kvm->arch.vmid.id);
+
+	kvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);
 
 	if (!kvm_riscv_gstage_vmid_bits())
 		kvm_riscv_local_hfence_gvma_all();
diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c
index 2ae34632cdcb1..b85e5ba2198aa 100644
--- a/arch/riscv/kvm/tlb.c
+++ b/arch/riscv/kvm/tlb.c
@@ -224,7 +224,7 @@ void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)
 	 * entries by VMID whenever underlying Host CPU changes for a VCPU.
 	 */
 
-	vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+	vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&vcpu->kvm->arch.vmid.id));
 	kvm_riscv_local_hfence_gvma_vmid_all(vmid);
 
 	/*
@@ -244,7 +244,7 @@ void kvm_riscv_fence_i_process(struct kvm_vcpu *vcpu)
 void kvm_riscv_tlb_flush_process(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vmid *v = &vcpu->kvm->arch.vmid;
-	unsigned long vmid = READ_ONCE(v->vmid);
+	unsigned long vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&v->id));
 
 	if (kvm_riscv_nacl_available())
 		nacl_hfence_gvma_vmid_all(nacl_shmem(), vmid);
@@ -255,7 +255,7 @@ void kvm_riscv_tlb_flush_process(struct kvm_vcpu *vcpu)
 void kvm_riscv_hfence_vvma_all_process(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vmid *v = &vcpu->kvm->arch.vmid;
-	unsigned long vmid = READ_ONCE(v->vmid);
+	unsigned long vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&v->id));
 
 	if (kvm_riscv_nacl_available())
 		nacl_hfence_vvma_all(nacl_shmem(), vmid);
@@ -531,8 +531,11 @@ void kvm_riscv_hfence_vvma_all(struct kvm *kvm,
 
 int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages)
 {
+	unsigned long vmid =
+		kvm_riscv_gstage_vmid_hwid(atomic64_read(&kvm->arch.vmid.id));
+
 	kvm_riscv_hfence_gvma_vmid_gpa(kvm, -1UL, 0,
 				       gfn << PAGE_SHIFT, nr_pages << PAGE_SHIFT,
-				       PAGE_SHIFT, READ_ONCE(kvm->arch.vmid.vmid));
+				       PAGE_SHIFT, vmid);
 	return 0;
 }
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index e062ca19f9d8f..85542c1a5ec3f 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -943,14 +943,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 			continue;
 		ret = 1;
 
-		kvm_riscv_gstage_vmid_update(vcpu);
-
 		ret = kvm_riscv_check_vcpu_requests(vcpu);
 		if (ret <= 0)
 			continue;
 
 		preempt_disable();
 
+		kvm_riscv_gstage_vmid_update(vcpu);
+
 		/* Update AIA HW state before entering guest */
 		ret = kvm_riscv_vcpu_aia_update(vcpu);
 		if (ret <= 0) {
diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c
index 506a510b6bff3..1be386a78e27f 100644
--- a/arch/riscv/kvm/vcpu_sbi_replace.c
+++ b/arch/riscv/kvm/vcpu_sbi_replace.c
@@ -104,7 +104,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run
 		kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_FENCE_I_SENT);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
-		vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+		vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&vcpu->kvm->arch.vmid.id));
 		if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL)
 			kvm_riscv_hfence_vvma_all(vcpu->kvm, hbase, hmask, vmid);
 		else
@@ -113,7 +113,7 @@ static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run
 		kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_SENT);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
-		vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+		vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&vcpu->kvm->arch.vmid.id));
 		if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL)
 			kvm_riscv_hfence_vvma_asid_all(vcpu->kvm, hbase, hmask,
 						       cp->a4, vmid);
diff --git a/arch/riscv/kvm/vcpu_sbi_v01.c b/arch/riscv/kvm/vcpu_sbi_v01.c
index de544ea3f28dc..ca3efe63c1cf1 100644
--- a/arch/riscv/kvm/vcpu_sbi_v01.c
+++ b/arch/riscv/kvm/vcpu_sbi_v01.c
@@ -88,14 +88,14 @@ static int kvm_sbi_ext_v01_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		if (cp->a7 == SBI_EXT_0_1_REMOTE_FENCE_I)
 			kvm_riscv_fence_i(vcpu->kvm, hbase, hmask);
 		else if (cp->a7 == SBI_EXT_0_1_REMOTE_SFENCE_VMA) {
-			vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+			vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&vcpu->kvm->arch.vmid.id));
 			if (cp->a1 == 0 && cp->a2 == 0)
 				kvm_riscv_hfence_vvma_all(vcpu->kvm, hbase, hmask, vmid);
 			else
 				kvm_riscv_hfence_vvma_gva(vcpu->kvm, hbase, hmask, cp->a1,
 							  cp->a2, PAGE_SHIFT, vmid);
 		} else {
-			vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+			vmid = kvm_riscv_gstage_vmid_hwid(atomic64_read(&vcpu->kvm->arch.vmid.id));
 			if (cp->a1 == 0 && cp->a2 == 0)
 				kvm_riscv_hfence_vvma_asid_all(vcpu->kvm, hbase, hmask,
 							       cp->a3, vmid);
diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c
index c15bdb1dd8bef..eee8306c12707 100644
--- a/arch/riscv/kvm/vmid.c
+++ b/arch/riscv/kvm/vmid.c
@@ -6,11 +6,15 @@
  *     Anup Patel <anup.patel@wdc.com>
  */
 
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
+#include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/kvm_host.h>
 #include <asm/csr.h>
@@ -18,26 +22,54 @@
 #include <asm/kvm_tlb.h>
 #include <asm/kvm_vmid.h>
 
-static unsigned long vmid_version = 1;
-static unsigned long vmid_next;
+static atomic64_t vmid_generation;
+static unsigned long *vmid_map;
 static unsigned long vmid_bits __ro_after_init;
-static DEFINE_SPINLOCK(vmid_lock);
+static unsigned long vmid_cur_idx = 1;
+
+static DEFINE_RAW_SPINLOCK(vmid_lock);
+
+static DEFINE_PER_CPU(atomic64_t, active_vmids);
+static DEFINE_PER_CPU(u64, reserved_vmids);
+
+static cpumask_t tlb_flush_pending;
+
+#define VMID_FIRST_VERSION	BIT_ULL(vmid_bits)
+#define NUM_VMIDS		BIT(vmid_bits)
+#define VMID_HW_MASK		(VMID_FIRST_VERSION - 1)
+
+static bool vmid_gen_match(u64 vmid)
+{
+	return !((vmid ^ atomic64_read(&vmid_generation)) >> vmid_bits);
+}
+
+unsigned long kvm_riscv_gstage_vmid_hwid(u64 vmid)
+{
+	if (!vmid_bits)
+		return 0;
+
+	return (unsigned long)(vmid & VMID_HW_MASK);
+}
 
 void __init kvm_riscv_gstage_vmid_detect(void)
 {
-	/* Figure-out number of VMID bits in HW */
+	/* Figure out the number of VMID bits supported by hardware. */
 	csr_write(CSR_HGATP, (kvm_riscv_gstage_mode(kvm_riscv_gstage_max_pgd_levels) <<
-			      HGATP_MODE_SHIFT) | HGATP_VMID);
+		   HGATP_MODE_SHIFT) | HGATP_VMID);
 	vmid_bits = csr_read(CSR_HGATP);
 	vmid_bits = (vmid_bits & HGATP_VMID) >> HGATP_VMID_SHIFT;
 	vmid_bits = fls_long(vmid_bits);
 	csr_write(CSR_HGATP, 0);
 
-	/* We polluted local TLB so flush all guest TLB */
+	/* Flush the local guest TLB after probing HGATP. */
 	kvm_riscv_local_hfence_gvma_all();
 
-	/* We don't use VMID bits if they are not sufficient */
-	if ((1UL << vmid_bits) < num_possible_cpus())
+	/*
+	 * VMID 0 is reserved.  During rollover every possible CPU may
+	 * reserve one hardware VMID, and we still need at least one VMID
+	 * available for a new allocation.
+	 */
+	if (vmid_bits && NUM_VMIDS - 1 <= num_possible_cpus())
 		vmid_bits = 0;
 }
 
@@ -46,80 +78,295 @@ unsigned long kvm_riscv_gstage_vmid_bits(void)
 	return vmid_bits;
 }
 
+int __init kvm_riscv_gstage_vmid_alloc_init(void)
+{
+	int cpu;
+
+	if (!vmid_bits)
+		return 0;
+
+	vmid_map = bitmap_zalloc(NUM_VMIDS, GFP_KERNEL);
+	if (!vmid_map)
+		return -ENOMEM;
+
+	vmid_cur_idx = 1;
+
+	/* Hardware VMID 0 is reserved. */
+	__set_bit(0, vmid_map);
+
+	atomic64_set(&vmid_generation, VMID_FIRST_VERSION);
+
+	for_each_possible_cpu(cpu) {
+		atomic64_set(&per_cpu(active_vmids, cpu), 0);
+		per_cpu(reserved_vmids, cpu) = 0;
+	}
+
+	/*
+	 * Every CPU performs an initial local invalidation before its
+	 * first VMID activation.
+	 */
+	cpumask_copy(&tlb_flush_pending, cpu_possible_mask);
+
+	return 0;
+}
+
+void kvm_riscv_gstage_vmid_alloc_free(void)
+{
+	bitmap_free(vmid_map);
+	vmid_map = NULL;
+}
+
 int kvm_riscv_gstage_vmid_init(struct kvm *kvm)
 {
-	/* Mark the initial VMID and VMID version invalid */
-	kvm->arch.vmid.vmid_version = 0;
-	kvm->arch.vmid.vmid = 0;
+	atomic64_set(&kvm->arch.vmid.id, 0);
 
 	return 0;
 }
 
 bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid)
 {
+	u64 id;
+
 	if (!vmid_bits)
 		return false;
 
-	return unlikely(READ_ONCE(vmid->vmid_version) !=
-			READ_ONCE(vmid_version));
+	id = atomic64_read(&vmid->id);
+
+	return unlikely(!vmid_gen_match(id));
 }
 
-static void __local_hfence_gvma_all(void *info)
+/*
+ * Called with vmid_lock held after vmid_generation has already been
+ * advanced.
+ *
+ * No remote CPU is interrupted here.  Instead, preserve every VMID
+ * which may still be used by a CPU and queue a local invalidation for
+ * that CPU's next VMID activation.
+ */
+static void flush_context(void)
 {
-	kvm_riscv_local_hfence_gvma_all();
+	u64 vmid;
+	int cpu;
+
+	bitmap_zero(vmid_map, NUM_VMIDS);
+	__set_bit(0, vmid_map);
+
+	for_each_possible_cpu(cpu) {
+		vmid = atomic64_xchg(&per_cpu(active_vmids, cpu), 0);
+
+		/*
+		 * The CPU may already have been caught by an earlier rollover
+		 * without performing another activation since then.  In that
+		 * case reserved_vmids is the only record of the old context.
+		 */
+		if (!vmid)
+			vmid = per_cpu(reserved_vmids, cpu);
+
+		if (vmid)
+			__set_bit(kvm_riscv_gstage_vmid_hwid(vmid),
+				  vmid_map);
+
+		per_cpu(reserved_vmids, cpu) = vmid;
+	}
+
+	cpumask_copy(&tlb_flush_pending, cpu_possible_mask);
 }
 
-void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)
+/*
+ * Update every reserved copy of an old software VMID.
+ *
+ * Do not stop after the first match: the same VM may have been active
+ * on more than one CPU when rollover occurred.
+ */
+static bool check_update_reserved_vmid(u64 old_vmid, u64 new_vmid)
 {
-	unsigned long i;
-	struct kvm_vcpu *v;
-	struct kvm_vmid *vmid = &vcpu->kvm->arch.vmid;
+	bool hit = false;
+	int cpu;
 
-	if (!kvm_riscv_gstage_vmid_ver_changed(vmid))
-		return;
+	for_each_possible_cpu(cpu) {
+		if (per_cpu(reserved_vmids, cpu) == old_vmid) {
+			per_cpu(reserved_vmids, cpu) = new_vmid;
+			hit = true;
+		}
+	}
+
+	return hit;
+}
+
+/*
+ * Allocate/promote a software VMID.
+ *
+ * vmid_lock must be held by the caller.
+ */
+static u64 new_vmid_locked(struct kvm_vmid *kvm_vmid)
+{
+	u64 vmid = atomic64_read(&kvm_vmid->id);
+	u64 generation = atomic64_read(&vmid_generation);
+	u64 new_vmid;
+	unsigned long idx;
 
-	spin_lock(&vmid_lock);
+	if (vmid) {
+		new_vmid = generation |
+			   kvm_riscv_gstage_vmid_hwid(vmid);
+
+		/*
+		 * The old VMID is still protected by one or more CPUs.
+		 * Keep the same hardware VMID and only promote generation.
+		 */
+		if (check_update_reserved_vmid(vmid, new_vmid))
+			return new_vmid;
+
+		/*
+		 * The VM had a VMID in an older generation.  Reuse the same
+		 * hardware number if it has not already been claimed.
+		 */
+		idx = kvm_riscv_gstage_vmid_hwid(vmid);
+		if (!__test_and_set_bit(idx, vmid_map))
+			return new_vmid;
+	}
+
+	/*
+	 * Find a free VMID in the current generation.
+	 */
+	idx = find_next_zero_bit(vmid_map, NUM_VMIDS, vmid_cur_idx);
+	if (idx != NUM_VMIDS)
+		goto set_vmid;
+
+	/*
+	 * No free VMID.  Start a new generation, preserve all CPU-local
+	 * users, and defer each CPU's flush until its next activation.
+	 */
+	generation += VMID_FIRST_VERSION;
+
+	/* Software VMID 0 is reserved as the invalid identifier. */
+	if (unlikely(!generation))
+		generation = VMID_FIRST_VERSION;
+
+	atomic64_xchg(&vmid_generation, generation);
+	flush_context();
 
 	/*
-	 * We need to re-check the vmid_version here to ensure that if
-	 * another vcpu already allocated a valid vmid for this vm.
+	 * NUM_VMIDS - 1 > num_possible_cpus(), therefore rollover must
+	 * leave at least one allocatable hardware VMID.
 	 */
-	if (!kvm_riscv_gstage_vmid_ver_changed(vmid)) {
-		spin_unlock(&vmid_lock);
+	idx = find_next_zero_bit(vmid_map, NUM_VMIDS, 1);
+
+set_vmid:
+	__set_bit(idx, vmid_map);
+	vmid_cur_idx = idx;
+
+	return generation | idx;
+}
+
+void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vmid *kvm_vmid = &vcpu->kvm->arch.vmid;
+	atomic64_t *active;
+	unsigned long flags;
+	u64 vmid;
+	u64 old_active_vmid;
+	unsigned int cpu;
+
+	if (!vmid_bits)
 		return;
-	}
 
-	/* First user of a new VMID version? */
-	if (unlikely(vmid_next == 0)) {
-		WRITE_ONCE(vmid_version, READ_ONCE(vmid_version) + 1);
-		vmid_next = 1;
+	/*
+	 * active_vmids and tlb_flush_pending are per-CPU state.  Keep the
+	 * complete VMID activation on the same CPU.
+	 */
+	lockdep_assert_preemption_disabled();
+
+	cpu = smp_processor_id();
+	active = this_cpu_ptr(&active_vmids);
+
+	vmid = atomic64_read(&kvm_vmid->id);
+	old_active_vmid = atomic64_read(active);
 
+	/*
+	 * Fast path.
+	 *
+	 * The cmpxchg races with flush_context()'s xchg on the same
+	 * per-CPU atomic.  Either this activation is captured by rollover,
+	 * or rollover clears active first and the cmpxchg fails.
+	 */
+	if (old_active_vmid && vmid_gen_match(vmid)) {
 		/*
-		 * We ran out of VMIDs so we increment vmid_version and
-		 * start assigning VMIDs from 1.
-		 *
-		 * This also means existing VMIDs assignment to all Guest
-		 * instances is invalid and we have force VMID re-assignement
-		 * for all Guest instances. The Guest instances that were not
-		 * running will automatically pick-up new VMIDs because will
-		 * call kvm_riscv_gstage_vmid_update() whenever they enter
-		 * in-kernel run loop. For Guest instances that are already
-		 * running, we force VM exits on all host CPUs using IPI and
-		 * flush all Guest TLBs.
+		 * HGATP must contain the same hardware VMID that is published
+		 * in active_vmids.
 		 */
-		on_each_cpu_mask(cpu_online_mask, __local_hfence_gvma_all,
-				 NULL, 1);
+		if (old_active_vmid != vmid)
+			kvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);
+
+		if (atomic64_cmpxchg(active, old_active_vmid, vmid) ==
+		    old_active_vmid)
+			return;
 	}
 
-	vmid->vmid = vmid_next;
-	vmid_next++;
-	vmid_next &= (1 << vmid_bits) - 1;
+	raw_spin_lock_irqsave(&vmid_lock, flags);
 
-	WRITE_ONCE(vmid->vmid_version, READ_ONCE(vmid_version));
+	/*
+	 * Re-read under the allocator lock because another vCPU of this VM
+	 * may already have promoted or allocated the shared VMID.
+	 */
+	vmid = atomic64_read(&kvm_vmid->id);
+
+	if (!vmid_gen_match(vmid)) {
+		vmid = new_vmid_locked(kvm_vmid);
+		atomic64_set(&kvm_vmid->id, vmid);
+	}
+
+	/*
+	 * Complete this CPU's deferred rollover invalidation before
+	 * installing the new hardware VMID.
+	 */
+	if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
+		kvm_riscv_local_hfence_gvma_all();
+
+	/*
+	 * Install the current hardware VMID before publishing this CPU as
+	 * active with the new software VMID.
+	 */
+	kvm_riscv_mmu_update_hgatp_vmid(vcpu, vmid);
+
+	/*
+	 * Once active_vmids is visible, the required local invalidation and
+	 * HGATP update are complete.
+	 */
+	atomic64_set(active, vmid);
+
+	raw_spin_unlock_irqrestore(&vmid_lock, flags);
+}
 
-	spin_unlock(&vmid_lock);
+/*
+ * CPU virtualization/CSR state is being discarded.
+ *
+ * Withdraw fast-path eligibility, but conservatively preserve the last
+ * identity instead of making its hardware VMID immediately reusable.
+ */
+void kvm_riscv_gstage_vmid_cpu_invalidate(void)
+{
+	unsigned long flags;
+	u64 vmid;
+	unsigned int cpu;
+
+	if (!vmid_bits)
+		return;
+
+	lockdep_assert_preemption_disabled();
+
+	cpu = smp_processor_id();
+
+	raw_spin_lock_irqsave(&vmid_lock, flags);
+
+	vmid = atomic64_xchg(this_cpu_ptr(&active_vmids), 0);
+
+	if (vmid)
+		per_cpu(reserved_vmids, cpu) = vmid;
+
+	/*
+	 * If active was already zero, retain the old reserved entry.
+	 */
+	cpumask_set_cpu(cpu, &tlb_flush_pending);
 
-	/* Request G-stage page table update for all VCPUs */
-	kvm_for_each_vcpu(i, v, vcpu->kvm)
-		kvm_make_request(KVM_REQ_UPDATE_HGATP, v);
+	raw_spin_unlock_irqrestore(&vmid_lock, flags);
 }

3/2 2026/09/11 16:20 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 12311
							output: 78
							thoughts: 880
						

Thoughts:
**Analysis of the Patch for Fuzzing Suitability**

Okay, let's take a look at this patch. It's touching a bunch of files under `arch/riscv/`, specifically related to KVM – `kvm_gstage.h`, `kvm_mmu.h`, `kvm_vmid.h`, and various `.c` files in `kvm/`.  Hang on, target architecture is `amd64`?  Right, so we need to determine if this is fuzzable on amd64.

Let's quickly reference the negative criteria. The key point is "Code paths exclusive to architectures other than the target architecture."  And yep, the target is amd64, and *all* the changed files are in `arch/riscv/`.  This is a slam dunk.  RISC-V KVM code is *not* compiled or reachable on amd64, so it's irrelevant for fuzzing on this architecture. I've double-checked the git diff just to be completely sure; every single file resides under the `arch/riscv/` directory.

Okay, so this patch falls squarely under the "unreachable execution paths" criteria.  Specifically, it's code exclusive to a different architecture, which is the negative criterion. Therefore, this patch isn't worth fuzzing on amd64.

Based on that, I can definitively set `WorthFuzzing` to `false`. Since this is unreachable, no specific configurations or symbols are relevant. Thus, `EnableConfigs` and `FocusSymbols` will be empty lists. And my reasoning will be concise: "All changes are confined to `arch/riscv/` (RISC-V KVM implementation), which is exclusive to the RISC-V architecture. Since the target architecture is amd64, the modified code is structurally unreachable and cannot be fuzzed."  I just verified the fields from the set-results with `EnableConfigs: []`, `FocusSymbols: []`, `Reasoning: "All changes are confined to arch/riscv/ (RISC-V KVM implementation), which is exclusive to the RISC-V architecture. Since the target architecture is amd64, the modified code is structurally unreachable and cannot be fuzzed."` and `WorthFuzzing: false`.



4/2 2026/09/11 16:20 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "All modified files are located in arch/riscv/ (RISC-V KVM subsystem). Because the target architecture is amd64, these code paths are exclusive to RISC-V and structurally unreachable on amd64.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "All modified files are located in arch/riscv/ (RISC-V KVM subsystem). Because the target architecture is amd64, these code paths are exclusive to RISC-V and structurally unreachable on amd64.",
  "WorthFuzzing": false
}

5/1 2026/09/11 16:20 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)