| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/24 17:26 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only modifies KVM selftests in tools/testing/selftests/kvm/, which is userspace testing code and does not alter any functional kernel logic.",
"WorthFuzzing": false
} |
| 1/1 | 2026/06/24 17:26 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 9b25fec9adec05070798d3e501037912a6af07e6\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Jun 24 17:26:12 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c\nindex 4415c94b286605..f78d56265d8936 100644\n--- a/tools/testing/selftests/kvm/access_tracking_perf_test.c\n+++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c\n@@ -409,7 +409,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \tint nr_vcpus = params-\u003enr_vcpus;\n \n \tvm = memstress_create_vm(mode, nr_vcpus, params-\u003evcpu_memory_bytes, 1,\n-\t\t\t\t params-\u003ebacking_src, !overlap_memory_access);\n+\t\t\t\t params-\u003ebacking_src, !overlap_memory_access, 0);\n \n \t/*\n \t * If guest_page_size is larger than the host's page size, the\ndiff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c\nindex 302c4923d0930f..92246e27ef7447 100644\n--- a/tools/testing/selftests/kvm/demand_paging_test.c\n+++ b/tools/testing/selftests/kvm/demand_paging_test.c\n@@ -162,7 +162,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \tint i, num_uffds = 0;\n \n \tvm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,\n-\t\t\t\t p-\u003esrc_type, p-\u003epartition_vcpu_memory_access);\n+\t\t\t\t p-\u003esrc_type, p-\u003epartition_vcpu_memory_access, 0);\n \n \tdemand_paging_size = get_backing_src_pagesz(p-\u003esrc_type);\n \ndiff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c\nindex ef779fa91827c9..659efa679bc744 100644\n--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c\n+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c\n@@ -13,6 +13,7 @@\n #include \u003ctime.h\u003e\n #include \u003cpthread.h\u003e\n #include \u003clinux/bitmap.h\u003e\n+#include \u003casm/barrier.h\u003e\n \n #include \"kvm_util.h\"\n #include \"test_util.h\"\n@@ -29,9 +30,43 @@ static bool run_vcpus_while_disabling_dirty_logging;\n \n /* Host variables */\n static u64 dirty_log_manual_caps;\n+static u32 dirty_ring_size;\n static bool host_quit;\n static int iteration;\n static int vcpu_last_completed_iteration[KVM_MAX_VCPUS];\n+static struct timespec vcpu_dirty_ring_collect[KVM_MAX_VCPUS];\n+\n+static void dirty_ring_collect(struct kvm_vcpu *vcpu, u32 *ring_idx,\n+\t\t\t\tstruct timespec *ts)\n+{\n+\tstruct timespec start;\n+\tstruct kvm_dirty_gfn *dirty_gfns = vcpu_map_dirty_ring(vcpu);\n+\tu32 ret, idx = *ring_idx;\n+\tu32 ring_size = vcpu-\u003evm-\u003edirty_ring_size;\n+\n+\tclock_gettime(CLOCK_MONOTONIC, \u0026start);\n+\n+\twhile (true) {\n+\t\tstruct kvm_dirty_gfn *cur;\n+\n+\t\tcur = \u0026dirty_gfns[idx % ring_size];\n+\t\tif (smp_load_acquire(\u0026cur-\u003eflags) != KVM_DIRTY_GFN_F_DIRTY)\n+\t\t\tbreak;\n+\n+\t\tsmp_store_release(\u0026cur-\u003eflags, KVM_DIRTY_GFN_F_RESET);\n+\t\tidx++;\n+\t}\n+\n+\tidx -= *ring_idx;\n+\t*ring_idx += idx;\n+\n+\tret = kvm_vm_reset_dirty_ring(vcpu-\u003evm);\n+\n+\tTEST_ASSERT(ret == idx, \"Reset dirty pages (%u) mismatch \"\n+\t\t \"with collected (%u)\", ret, idx);\n+\n+\t*ts = timespec_add(*ts, timespec_elapsed(start));\n+}\n \n static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)\n {\n@@ -43,19 +78,36 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)\n \tstruct timespec ts_diff;\n \tstruct timespec total = (struct timespec){0};\n \tstruct timespec avg;\n+\tbool use_dirty_ring = !!vcpu-\u003evm-\u003edirty_ring_size;\n+\tu32 ring_idx = 0;\n \tint ret;\n \n \trun = vcpu-\u003erun;\n \n \twhile (!READ_ONCE(host_quit)) {\n \t\tint current_iteration = READ_ONCE(iteration);\n+\t\tstruct timespec collect = (struct timespec){0};\n \n \t\tclock_gettime(CLOCK_MONOTONIC, \u0026start);\n-\t\tret = _vcpu_run(vcpu);\n+\n+\t\tdo {\n+\t\t\tret = _vcpu_run(vcpu);\n+\t\t\tif (!use_dirty_ring)\n+\t\t\t\tbreak;\n+\n+\t\t\tdirty_ring_collect(vcpu, \u0026ring_idx, \u0026collect);\n+\t\t} while (ret == KVM_EXIT_DIRTY_RING_FULL);\n+\n \t\tts_diff = timespec_elapsed(start);\n \n+\t\tif (use_dirty_ring) {\n+\t\t\tts_diff = timespec_sub(ts_diff, collect);\n+\t\t\tvcpu_dirty_ring_collect[vcpu_idx] = collect;\n+\t\t}\n+\n \t\tTEST_ASSERT(ret == 0, \"vcpu_run failed: %d\", ret);\n-\t\tTEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC,\n+\t\tTEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC ||\n+\t\t\t (use_dirty_ring \u0026\u0026 run-\u003eexit_reason == KVM_EXIT_DIRTY_RING_FULL),\n \t\t\t \"Invalid guest sync status: exit_reason=%s\",\n \t\t\t exit_reason_str(run-\u003eexit_reason));\n \n@@ -119,7 +171,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \n \tvm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size,\n \t\t\t\t p-\u003eslots, p-\u003ebacking_src,\n-\t\t\t\t p-\u003epartition_vcpu_memory_access);\n+\t\t\t\t p-\u003epartition_vcpu_memory_access,\n+\t\t\t\t dirty_ring_size);\n \n \tmemstress_set_write_percent(vm, p-\u003ewrite_percent);\n \n@@ -139,8 +192,10 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \thost_quit = false;\n \n \tclock_gettime(CLOCK_MONOTONIC, \u0026start);\n-\tfor (i = 0; i \u003c nr_vcpus; i++)\n+\tfor (i = 0; i \u003c nr_vcpus; i++) {\n \t\tvcpu_last_completed_iteration[i] = -1;\n+\t\tvcpu_dirty_ring_collect[i] = (struct timespec){0};\n+\t}\n \n \t/*\n \t * Use 100% writes during the population phase to ensure all\n@@ -195,6 +250,21 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \t\tpr_info(\"Iteration %d dirty memory time: %ld.%.9lds\\n\",\n \t\t\titeration, ts_diff.tv_sec, ts_diff.tv_nsec);\n \n+\t\tif (dirty_ring_size) {\n+\t\t\tstruct timespec iteration_sum = (struct timespec){0};\n+\n+\t\t\tfor (i = 0; i \u003c nr_vcpus; i++)\n+\t\t\t\titeration_sum = timespec_add(iteration_sum,\n+\t\t\t\t\t\t\t vcpu_dirty_ring_collect[i]);\n+\n+\t\t\tpr_info(\"Iteration %d clear dirty ring time: %ld.%.9lds\\n\",\n+\t\t\t\titeration, iteration_sum.tv_sec, iteration_sum.tv_nsec);\n+\n+\t\t\tclear_dirty_log_total = timespec_add(clear_dirty_log_total,\n+\t\t\t\t\t\t\t iteration_sum);\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\tclock_gettime(CLOCK_MONOTONIC, \u0026start);\n \t\tmemstress_get_dirty_log(vm, bitmaps, p-\u003eslots);\n \t\tts_diff = timespec_elapsed(start);\n@@ -238,12 +308,14 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \thost_quit = true;\n \tmemstress_join_vcpu_threads(nr_vcpus);\n \n-\tavg = timespec_div(get_dirty_log_total, p-\u003eiterations);\n-\tpr_info(\"Get dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\\n\",\n-\t\tp-\u003eiterations, get_dirty_log_total.tv_sec,\n-\t\tget_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec);\n+\tif (!dirty_ring_size) {\n+\t\tavg = timespec_div(get_dirty_log_total, p-\u003eiterations);\n+\t\tpr_info(\"Get dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\\n\",\n+\t\t\tp-\u003eiterations, get_dirty_log_total.tv_sec,\n+\t\t\tget_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec);\n+\t}\n \n-\tif (dirty_log_manual_caps) {\n+\tif (dirty_log_manual_caps || dirty_ring_size) {\n \t\tavg = timespec_div(clear_dirty_log_total, p-\u003eiterations);\n \t\tpr_info(\"Clear dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\\n\",\n \t\t\tp-\u003eiterations, clear_dirty_log_total.tv_sec,\n@@ -264,6 +336,9 @@ static void help(char *name)\n \tprintf(\" -a: access memory randomly rather than in order.\\n\");\n \tprintf(\" -i: specify iteration counts (default: %\"PRIu64\")\\n\",\n \t TEST_HOST_LOOP_N);\n+\tprintf(\" -d: specify the size of dirty-ring for tracking dirty pages.\\n\"\n+\t \" If non-zero, will cause dirty-ring to be used instead of\\n\"\n+\t \" dirty-bitmap. Must be a power of two.\");\n \tprintf(\" -g: Do not enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2. This\\n\"\n \t \" makes KVM_GET_DIRTY_LOG clear the dirty log (i.e.\\n\"\n \t \" KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE is not enabled)\\n\"\n@@ -320,7 +395,7 @@ int main(int argc, char *argv[])\n \n \tguest_modes_append_default();\n \n-\twhile ((opt = getopt(argc, argv, \"ab:c:eghi:m:nop:r:s:v:x:w:\")) != -1) {\n+\twhile ((opt = getopt(argc, argv, \"ab:c:d:eghi:m:nop:r:s:v:x:w:\")) != -1) {\n \t\tswitch (opt) {\n \t\tcase 'a':\n \t\t\tp.random_access = true;\n@@ -331,6 +406,11 @@ int main(int argc, char *argv[])\n \t\tcase 'c':\n \t\t\tpcpu_list = optarg;\n \t\t\tbreak;\n+\t\tcase 'd':\n+\t\t\tdirty_ring_size = parse_size(optarg);\n+\t\t\tdirty_ring_size *= sizeof(struct kvm_dirty_gfn);\n+\t\t\tdirty_log_manual_caps = 0;\n+\t\t\tbreak;\n \t\tcase 'e':\n \t\t\t/* 'e' is for evil. */\n \t\t\trun_vcpus_while_disabling_dirty_logging = true;\ndiff --git a/tools/testing/selftests/kvm/include/memstress.h b/tools/testing/selftests/kvm/include/memstress.h\nindex 0d1d6230cc051b..e17f344978af66 100644\n--- a/tools/testing/selftests/kvm/include/memstress.h\n+++ b/tools/testing/selftests/kvm/include/memstress.h\n@@ -58,7 +58,8 @@ extern struct memstress_args memstress_args;\n struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,\n \t\t\t\t u64 vcpu_memory_bytes, int slots,\n \t\t\t\t enum vm_mem_backing_src_type backing_src,\n-\t\t\t\t bool partition_vcpu_memory_access);\n+\t\t\t\t bool partition_vcpu_memory_access,\n+\t\t\t\t u32 dirty_ring_size);\n void memstress_destroy_vm(struct kvm_vm *vm);\n \n void memstress_set_write_percent(struct kvm_vm *vm, u32 write_percent);\ndiff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c\nindex 195f3fdae1e396..237f0ce0ae6006 100644\n--- a/tools/testing/selftests/kvm/lib/kvm_util.c\n+++ b/tools/testing/selftests/kvm/lib/kvm_util.c\n@@ -167,10 +167,20 @@ unsigned int kvm_check_cap(long cap)\n \n void vm_enable_dirty_ring(struct kvm_vm *vm, u32 ring_size)\n {\n-\tif (vm_check_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL))\n-\t\tvm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL, ring_size);\n-\telse\n-\t\tvm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING, ring_size);\n+\tlong cap = KVM_CAP_DIRTY_LOG_RING_ACQ_REL;\n+\tint max_size = vm_check_cap(vm, cap);\n+\n+\tif (!max_size) {\n+\t\tcap = KVM_CAP_DIRTY_LOG_RING;\n+\t\tmax_size = vm_check_cap(vm, cap);\n+\t}\n+\n+\tTEST_ASSERT(ring_size \u003c= max_size \u0026\u0026 is_power_of_2(ring_size),\n+\t\t \"Invalid dirty-ring size: Should be a power of two \"\n+\t\t \"smaller than %d entries\\n\",\n+\t\t max_size / sizeof(struct kvm_dirty_gfn));\n+\n+\tvm_enable_cap(vm, cap, ring_size);\n \tvm-\u003edirty_ring_size = ring_size;\n }\n \ndiff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c\nindex 6dcd15910a0608..c9f85533ffffdc 100644\n--- a/tools/testing/selftests/kvm/lib/memstress.c\n+++ b/tools/testing/selftests/kvm/lib/memstress.c\n@@ -121,10 +121,35 @@ void memstress_setup_vcpus(struct kvm_vm *vm, int nr_vcpus,\n \t}\n }\n \n+static struct kvm_vm *memstress_vm_create_with_vcpus(struct vm_shape shape,\n+\t\t\t\t\t\t u32 nr_vcpus,\n+\t\t\t\t\t\t u64 extra_mem_pages,\n+\t\t\t\t\t\t void *guest_code,\n+\t\t\t\t\t\t struct kvm_vcpu *vcpus[],\n+\t\t\t\t\t\t u32 dirty_ring_size)\n+{\n+\tstruct kvm_vm *vm;\n+\tint i;\n+\n+\tTEST_ASSERT(!nr_vcpus || vcpus, \"Must provide vCPU array\");\n+\n+\tvm = __vm_create(shape, nr_vcpus, extra_mem_pages);\n+\n+\tif (dirty_ring_size)\n+\t\tvm_enable_dirty_ring(vm, dirty_ring_size);\n+\n+\tfor (i = 0; i \u003c nr_vcpus; ++i)\n+\t\tvcpus[i] = vm_vcpu_add(vm, i, guest_code);\n+\n+\tkvm_arch_vm_finalize_vcpus(vm);\n+\treturn vm;\n+}\n+\n struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,\n \t\t\t\t u64 vcpu_memory_bytes, int slots,\n \t\t\t\t enum vm_mem_backing_src_type backing_src,\n-\t\t\t\t bool partition_vcpu_memory_access)\n+\t\t\t\t bool partition_vcpu_memory_access,\n+\t\t\t\t u32 dirty_ring_size)\n {\n \tstruct memstress_args *args = \u0026memstress_args;\n \tstruct kvm_vm *vm;\n@@ -167,9 +192,10 @@ struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,\n \t * The memory is also added to memslot 0, but that's a benign side\n \t * effect as KVM allows aliasing HVAs in meslots.\n \t */\n-\tvm = __vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus,\n-\t\t\t\t slot0_pages + guest_num_pages,\n-\t\t\t\t memstress_guest_code, vcpus);\n+\tvm = memstress_vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus,\n+\t\t\t\t\t slot0_pages + guest_num_pages,\n+\t\t\t\t\t memstress_guest_code, vcpus,\n+\t\t\t\t\t dirty_ring_size);\n \n \targs-\u003evm = vm;\n \ndiff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c\nindex 9c7578a098c3e1..3a1be9b75e01da 100644\n--- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c\n+++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c\n@@ -90,7 +90,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \n \tvm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,\n \t\t\t\t VM_MEM_SRC_ANONYMOUS,\n-\t\t\t\t p-\u003epartition_vcpu_memory_access);\n+\t\t\t\t p-\u003epartition_vcpu_memory_access, 0);\n #ifdef __x86_64__\n \tif (p-\u003edisable_slot_zap_quirk)\n \t\tvm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, KVM_X86_QUIRK_SLOT_ZAP_ALL);\ndiff --git a/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c b/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c\nindex 388ba4101f9736..661e9abfb4395d 100644\n--- a/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c\n+++ b/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c\n@@ -101,7 +101,7 @@ static void run_test(enum vm_guest_mode mode, void *unused)\n \tstruct kvm_page_stats stats_repopulated;\n \n \tvm = memstress_create_vm(mode, VCPUS, guest_percpu_mem_size,\n-\t\t\t\t SLOTS, backing_src, false);\n+\t\t\t\t SLOTS, backing_src, false, 0);\n \n \tguest_num_pages = (VCPUS * guest_percpu_mem_size) \u003e\u003e vm-\u003epage_shift;\n \tguest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);\n"
} |
| 2/1 | 2026/06/24 17:26 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only modifies KVM selftests in tools/testing/selftests/kvm/, which is userspace testing code and does not alter any functional kernel logic.",
"WorthFuzzing": false
}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 9b25fec9adec05070798d3e501037912a6af07e6
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Jun 24 17:26:12 2026 +0000
syz-cluster: applied patch under review
diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c
index 4415c94b286605..f78d56265d8936 100644
--- a/tools/testing/selftests/kvm/access_tracking_perf_test.c
+++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c
@@ -409,7 +409,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
int nr_vcpus = params->nr_vcpus;
vm = memstress_create_vm(mode, nr_vcpus, params->vcpu_memory_bytes, 1,
- params->backing_src, !overlap_memory_access);
+ params->backing_src, !overlap_memory_access, 0);
/*
* If guest_page_size is larger than the host's page size, the
diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c
index 302c4923d0930f..92246e27ef7447 100644
--- a/tools/testing/selftests/kvm/demand_paging_test.c
+++ b/tools/testing/selftests/kvm/demand_paging_test.c
@@ -162,7 +162,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
int i, num_uffds = 0;
vm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,
- p->src_type, p->partition_vcpu_memory_access);
+ p->src_type, p->partition_vcpu_memory_access, 0);
demand_paging_size = get_backing_src_pagesz(p->src_type);
diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index ef779fa91827c9..659efa679bc744 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -13,6 +13,7 @@
#include <time.h>
#include <pthread.h>
#include <linux/bitmap.h>
+#include <asm/barrier.h>
#include "kvm_util.h"
#include "test_util.h"
@@ -29,9 +30,43 @@ static bool run_vcpus_while_disabling_dirty_logging;
/* Host variables */
static u64 dirty_log_manual_caps;
+static u32 dirty_ring_size;
static bool host_quit;
static int iteration;
static int vcpu_last_completed_iteration[KVM_MAX_VCPUS];
+static struct timespec vcpu_dirty_ring_collect[KVM_MAX_VCPUS];
+
+static void dirty_ring_collect(struct kvm_vcpu *vcpu, u32 *ring_idx,
+ struct timespec *ts)
+{
+ struct timespec start;
+ struct kvm_dirty_gfn *dirty_gfns = vcpu_map_dirty_ring(vcpu);
+ u32 ret, idx = *ring_idx;
+ u32 ring_size = vcpu->vm->dirty_ring_size;
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ while (true) {
+ struct kvm_dirty_gfn *cur;
+
+ cur = &dirty_gfns[idx % ring_size];
+ if (smp_load_acquire(&cur->flags) != KVM_DIRTY_GFN_F_DIRTY)
+ break;
+
+ smp_store_release(&cur->flags, KVM_DIRTY_GFN_F_RESET);
+ idx++;
+ }
+
+ idx -= *ring_idx;
+ *ring_idx += idx;
+
+ ret = kvm_vm_reset_dirty_ring(vcpu->vm);
+
+ TEST_ASSERT(ret == idx, "Reset dirty pages (%u) mismatch "
+ "with collected (%u)", ret, idx);
+
+ *ts = timespec_add(*ts, timespec_elapsed(start));
+}
static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
{
@@ -43,19 +78,36 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
struct timespec ts_diff;
struct timespec total = (struct timespec){0};
struct timespec avg;
+ bool use_dirty_ring = !!vcpu->vm->dirty_ring_size;
+ u32 ring_idx = 0;
int ret;
run = vcpu->run;
while (!READ_ONCE(host_quit)) {
int current_iteration = READ_ONCE(iteration);
+ struct timespec collect = (struct timespec){0};
clock_gettime(CLOCK_MONOTONIC, &start);
- ret = _vcpu_run(vcpu);
+
+ do {
+ ret = _vcpu_run(vcpu);
+ if (!use_dirty_ring)
+ break;
+
+ dirty_ring_collect(vcpu, &ring_idx, &collect);
+ } while (ret == KVM_EXIT_DIRTY_RING_FULL);
+
ts_diff = timespec_elapsed(start);
+ if (use_dirty_ring) {
+ ts_diff = timespec_sub(ts_diff, collect);
+ vcpu_dirty_ring_collect[vcpu_idx] = collect;
+ }
+
TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret);
- TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC,
+ TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC ||
+ (use_dirty_ring && run->exit_reason == KVM_EXIT_DIRTY_RING_FULL),
"Invalid guest sync status: exit_reason=%s",
exit_reason_str(run->exit_reason));
@@ -119,7 +171,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
vm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size,
p->slots, p->backing_src,
- p->partition_vcpu_memory_access);
+ p->partition_vcpu_memory_access,
+ dirty_ring_size);
memstress_set_write_percent(vm, p->write_percent);
@@ -139,8 +192,10 @@ static void run_test(enum vm_guest_mode mode, void *arg)
host_quit = false;
clock_gettime(CLOCK_MONOTONIC, &start);
- for (i = 0; i < nr_vcpus; i++)
+ for (i = 0; i < nr_vcpus; i++) {
vcpu_last_completed_iteration[i] = -1;
+ vcpu_dirty_ring_collect[i] = (struct timespec){0};
+ }
/*
* Use 100% writes during the population phase to ensure all
@@ -195,6 +250,21 @@ static void run_test(enum vm_guest_mode mode, void *arg)
pr_info("Iteration %d dirty memory time: %ld.%.9lds\n",
iteration, ts_diff.tv_sec, ts_diff.tv_nsec);
+ if (dirty_ring_size) {
+ struct timespec iteration_sum = (struct timespec){0};
+
+ for (i = 0; i < nr_vcpus; i++)
+ iteration_sum = timespec_add(iteration_sum,
+ vcpu_dirty_ring_collect[i]);
+
+ pr_info("Iteration %d clear dirty ring time: %ld.%.9lds\n",
+ iteration, iteration_sum.tv_sec, iteration_sum.tv_nsec);
+
+ clear_dirty_log_total = timespec_add(clear_dirty_log_total,
+ iteration_sum);
+ continue;
+ }
+
clock_gettime(CLOCK_MONOTONIC, &start);
memstress_get_dirty_log(vm, bitmaps, p->slots);
ts_diff = timespec_elapsed(start);
@@ -238,12 +308,14 @@ static void run_test(enum vm_guest_mode mode, void *arg)
host_quit = true;
memstress_join_vcpu_threads(nr_vcpus);
- avg = timespec_div(get_dirty_log_total, p->iterations);
- pr_info("Get dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\n",
- p->iterations, get_dirty_log_total.tv_sec,
- get_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec);
+ if (!dirty_ring_size) {
+ avg = timespec_div(get_dirty_log_total, p->iterations);
+ pr_info("Get dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\n",
+ p->iterations, get_dirty_log_total.tv_sec,
+ get_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec);
+ }
- if (dirty_log_manual_caps) {
+ if (dirty_log_manual_caps || dirty_ring_size) {
avg = timespec_div(clear_dirty_log_total, p->iterations);
pr_info("Clear dirty log over %lu iterations took %ld.%.9lds. (Avg %ld.%.9lds/iteration)\n",
p->iterations, clear_dirty_log_total.tv_sec,
@@ -264,6 +336,9 @@ static void help(char *name)
printf(" -a: access memory randomly rather than in order.\n");
printf(" -i: specify iteration counts (default: %"PRIu64")\n",
TEST_HOST_LOOP_N);
+ printf(" -d: specify the size of dirty-ring for tracking dirty pages.\n"
+ " If non-zero, will cause dirty-ring to be used instead of\n"
+ " dirty-bitmap. Must be a power of two.");
printf(" -g: Do not enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2. This\n"
" makes KVM_GET_DIRTY_LOG clear the dirty log (i.e.\n"
" KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE is not enabled)\n"
@@ -320,7 +395,7 @@ int main(int argc, char *argv[])
guest_modes_append_default();
- while ((opt = getopt(argc, argv, "ab:c:eghi:m:nop:r:s:v:x:w:")) != -1) {
+ while ((opt = getopt(argc, argv, "ab:c:d:eghi:m:nop:r:s:v:x:w:")) != -1) {
switch (opt) {
case 'a':
p.random_access = true;
@@ -331,6 +406,11 @@ int main(int argc, char *argv[])
case 'c':
pcpu_list = optarg;
break;
+ case 'd':
+ dirty_ring_size = parse_size(optarg);
+ dirty_ring_size *= sizeof(struct kvm_dirty_gfn);
+ dirty_log_manual_caps = 0;
+ break;
case 'e':
/* 'e' is for evil. */
run_vcpus_while_disabling_dirty_logging = true;
diff --git a/tools/testing/selftests/kvm/include/memstress.h b/tools/testing/selftests/kvm/include/memstress.h
index 0d1d6230cc051b..e17f344978af66 100644
--- a/tools/testing/selftests/kvm/include/memstress.h
+++ b/tools/testing/selftests/kvm/include/memstress.h
@@ -58,7 +58,8 @@ extern struct memstress_args memstress_args;
struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,
u64 vcpu_memory_bytes, int slots,
enum vm_mem_backing_src_type backing_src,
- bool partition_vcpu_memory_access);
+ bool partition_vcpu_memory_access,
+ u32 dirty_ring_size);
void memstress_destroy_vm(struct kvm_vm *vm);
void memstress_set_write_percent(struct kvm_vm *vm, u32 write_percent);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 195f3fdae1e396..237f0ce0ae6006 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -167,10 +167,20 @@ unsigned int kvm_check_cap(long cap)
void vm_enable_dirty_ring(struct kvm_vm *vm, u32 ring_size)
{
- if (vm_check_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL))
- vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL, ring_size);
- else
- vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING, ring_size);
+ long cap = KVM_CAP_DIRTY_LOG_RING_ACQ_REL;
+ int max_size = vm_check_cap(vm, cap);
+
+ if (!max_size) {
+ cap = KVM_CAP_DIRTY_LOG_RING;
+ max_size = vm_check_cap(vm, cap);
+ }
+
+ TEST_ASSERT(ring_size <= max_size && is_power_of_2(ring_size),
+ "Invalid dirty-ring size: Should be a power of two "
+ "smaller than %d entries\n",
+ max_size / sizeof(struct kvm_dirty_gfn));
+
+ vm_enable_cap(vm, cap, ring_size);
vm->dirty_ring_size = ring_size;
}
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index 6dcd15910a0608..c9f85533ffffdc 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -121,10 +121,35 @@ void memstress_setup_vcpus(struct kvm_vm *vm, int nr_vcpus,
}
}
+static struct kvm_vm *memstress_vm_create_with_vcpus(struct vm_shape shape,
+ u32 nr_vcpus,
+ u64 extra_mem_pages,
+ void *guest_code,
+ struct kvm_vcpu *vcpus[],
+ u32 dirty_ring_size)
+{
+ struct kvm_vm *vm;
+ int i;
+
+ TEST_ASSERT(!nr_vcpus || vcpus, "Must provide vCPU array");
+
+ vm = __vm_create(shape, nr_vcpus, extra_mem_pages);
+
+ if (dirty_ring_size)
+ vm_enable_dirty_ring(vm, dirty_ring_size);
+
+ for (i = 0; i < nr_vcpus; ++i)
+ vcpus[i] = vm_vcpu_add(vm, i, guest_code);
+
+ kvm_arch_vm_finalize_vcpus(vm);
+ return vm;
+}
+
struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,
u64 vcpu_memory_bytes, int slots,
enum vm_mem_backing_src_type backing_src,
- bool partition_vcpu_memory_access)
+ bool partition_vcpu_memory_access,
+ u32 dirty_ring_size)
{
struct memstress_args *args = &memstress_args;
struct kvm_vm *vm;
@@ -167,9 +192,10 @@ struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,
* The memory is also added to memslot 0, but that's a benign side
* effect as KVM allows aliasing HVAs in meslots.
*/
- vm = __vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus,
- slot0_pages + guest_num_pages,
- memstress_guest_code, vcpus);
+ vm = memstress_vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus,
+ slot0_pages + guest_num_pages,
+ memstress_guest_code, vcpus,
+ dirty_ring_size);
args->vm = vm;
diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c
index 9c7578a098c3e1..3a1be9b75e01da 100644
--- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c
+++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c
@@ -90,7 +90,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
vm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,
VM_MEM_SRC_ANONYMOUS,
- p->partition_vcpu_memory_access);
+ p->partition_vcpu_memory_access, 0);
#ifdef __x86_64__
if (p->disable_slot_zap_quirk)
vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, KVM_X86_QUIRK_SLOT_ZAP_ALL);
diff --git a/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c b/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c
index 388ba4101f9736..661e9abfb4395d 100644
--- a/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c
+++ b/tools/testing/selftests/kvm/x86/dirty_log_page_splitting_test.c
@@ -101,7 +101,7 @@ static void run_test(enum vm_guest_mode mode, void *unused)
struct kvm_page_stats stats_repopulated;
vm = memstress_create_vm(mode, VCPUS, guest_percpu_mem_size,
- SLOTS, backing_src, false);
+ SLOTS, backing_src, false, 0);
guest_num_pages = (VCPUS * guest_percpu_mem_size) >> vm->page_shift;
guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
|
| 3/2 | 2026/06/24 17:26 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7140 output: 67 thoughts: 543 Thoughts: **WorthFuzzing Assessment: KVM Selftests Patch Series** Okay, I'm looking at this patch series modifying KVM selftests, specifically within `tools/testing/selftests/kvm/*`. Let me quickly confirm this; the diff includes changes to: `access_tracking_perf_test.c`, `demand_paging_test.c`, `dirty_log_perf_test.c`, `include/memstress.h`, `lib/kvm_util.c`, `lib/memstress.c`, `memslot_modification_stress_test.c`, and `x86/dirty_log_page_splitting_test.c`. Yes, it all seems isolated to that directory. Now, the instructions say to mark `WorthFuzzing=false` if the patch concerns things like documentation, Kconfig, comments, logging, decorative changes, or non-functional constants. It explicitly excludes modifications to code that can't be reached in a virtualized environment. Aha! These are *selftests*. Selftests are userspace programs designed to exercise and validate kernel functionality, but they are not themselves part of the kernel code. If the kernel logic isn't changed, there's no need to fuzz the kernel based on changes to these tests. Therefore, fuzzing the kernel based on these changes doesn't make sense. The kernel's core functionality hasn't been modified. Just to be absolutely sure, let me double-check that there aren't any other files involved. Nope, it's exclusively within `tools/testing/selftests/kvm/...`. The reasoning is pretty clear: This patch series is modifying user-space KVM selftests only. It does not alter any core kernel logic. Thus, `WorthFuzzing=false`. The `FocusSymbols` and `EnableConfigs` can be empty arrays as well. I'm going to set these results now. |
| 4/2 | 2026/06/24 17:26 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch only modifies KVM selftests in tools/testing/selftests/kvm/, which is userspace testing code and does not alter any functional kernel logic.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only modifies KVM selftests in tools/testing/selftests/kvm/, which is userspace testing code and does not alter any functional kernel logic.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|