AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch only modifies kho_reserve_scratch(), an __init function in kernel/liveupdate/kexec_handover.c that executes exclusively during early boot memory initialization (via mm_core_init) and is freed before userspace execution. Because this code cannot be triggered at runtime by syscalls, ioctls, or user-space interfaces, it is structurally unreachable to the fuzzer.",
  "WorthFuzzing": false
}

1/1 2026/09/05 11:49 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 8d103f755eb28e903edcd921dcad309e77fe8046\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Sep 5 11:49:26 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c\nindex 7c4d86daf86d5..39f489a258d90 100644\n--- a/kernel/liveupdate/kexec_handover.c\n+++ b/kernel/liveupdate/kexec_handover.c\n@@ -847,6 +847,17 @@ static void __init kho_reserve_scratch(void)\n \t\tgoto err_disable_kho;\n \t}\n \n+\t/*\n+\t * Calculate the per-node sizes before reserving any scratch areas.\n+\t * memblock allocations are marked MEMBLOCK_RSRV_KERN, so calculating\n+\t * them later would count the lowmem and global scratch areas as kernel\n+\t * allocations and scale them again.\n+\t */\n+\ti = 2;\n+\tfor_each_node_state(nid, N_MEMORY)\n+\t\tkho_scratch[i++].size = scratch_size_node(nid);\n+\ti = 0;\n+\n \t/*\n \t * reserve scratch area in low memory for lowmem allocations in the\n \t * next kernel\n@@ -880,7 +891,7 @@ static void __init kho_reserve_scratch(void)\n \t * memoryless nodes, as we can not allocate scratch areas there.\n \t */\n \tfor_each_node_state(nid, N_MEMORY) {\n-\t\tsize = scratch_size_node(nid);\n+\t\tsize = kho_scratch[i].size;\n \t\taddr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES,\n \t\t\t\t\t\t0, MEMBLOCK_ALLOC_ACCESSIBLE,\n \t\t\t\t\t\tnid, true);\n"
}

2/1 2026/09/05 11:49 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies kho_reserve_scratch(), an __init function in kernel/liveupdate/kexec_handover.c that executes exclusively during early boot memory initialization (via mm_core_init) and is freed before userspace execution. Because this code cannot be triggered at runtime by syscalls, ioctls, or user-space interfaces, it is structurally unreachable to the fuzzer.",
  "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 8d103f755eb28e903edcd921dcad309e77fe8046
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Sep 5 11:49:26 2026 +0000

    syz-cluster: applied patch under review

diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 7c4d86daf86d5..39f489a258d90 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -847,6 +847,17 @@ static void __init kho_reserve_scratch(void)
 		goto err_disable_kho;
 	}
 
+	/*
+	 * Calculate the per-node sizes before reserving any scratch areas.
+	 * memblock allocations are marked MEMBLOCK_RSRV_KERN, so calculating
+	 * them later would count the lowmem and global scratch areas as kernel
+	 * allocations and scale them again.
+	 */
+	i = 2;
+	for_each_node_state(nid, N_MEMORY)
+		kho_scratch[i++].size = scratch_size_node(nid);
+	i = 0;
+
 	/*
 	 * reserve scratch area in low memory for lowmem allocations in the
 	 * next kernel
@@ -880,7 +891,7 @@ static void __init kho_reserve_scratch(void)
 	 * memoryless nodes, as we can not allocate scratch areas there.
 	 */
 	for_each_node_state(nid, N_MEMORY) {
-		size = scratch_size_node(nid);
+		size = kho_scratch[i].size;
 		addr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES,
 						0, MEMBLOCK_ALLOC_ACCESSIBLE,
 						nid, true);

3/2 2026/09/05 11:49 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 3091
							output: 41
							thoughts: 104
						

Thoughts:
**Analyzing the kexec_handover Patch**

Alright, let's dive into this. My initial approach is to thoroughly analyze this patch. I'm starting by understanding the scope: what file was modified? Ah, `kernel/liveupdate/kexec_handover.c`. Okay, now we need to pinpoint the key areas. I need to focus on the `kho_reserve_scratch` function. I have to immediately grasp its context – how it's called, what configuration options govern its execution, and crucially, whether it's an early-boot, initialization function (`__init`), or if it's runtime code. This is essential for understanding the implications of any changes.

Let's get the specific code. Give me line 847 of `kernel/liveupdate/kexec_handover.c`. I need the code context to fully grasp the change.



4/2 2026/09/05 11:49 tool read-file
0m Args:
{
  "File": "kernel/liveupdate/kexec_handover.c",
  "FirstLine": 820,
  "LineCount": 100
}

Results:
{
  "Contents": " 820:\t}\n 821:\t\n 822:\t/**\n 823:\t * kho_reserve_scratch - Reserve a contiguous chunk of memory for kexec\n 824:\t *\n 825:\t * With KHO we can preserve arbitrary pages in the system. To ensure we still\n 826:\t * have a large contiguous region of memory when we search the physical address\n 827:\t * space for target memory, let's make sure we always have a large CMA region\n 828:\t * active. This CMA region will only be used for movable pages which are not a\n 829:\t * problem for us during KHO because we can just move them somewhere else.\n 830:\t */\n 831:\tstatic void __init kho_reserve_scratch(void)\n 832:\t{\n 833:\t\tphys_addr_t addr, size;\n 834:\t\tint nid, i = 0;\n 835:\t\n 836:\t\tif (!kho_enable)\n 837:\t\t\treturn;\n 838:\t\n 839:\t\tscratch_size_update();\n 840:\t\n 841:\t\t/* FIXME: deal with node hot-plug/remove */\n 842:\t\tkho_scratch_cnt = nodes_weight(node_states[N_MEMORY]) + 2;\n 843:\t\tsize = kho_scratch_cnt * sizeof(*kho_scratch);\n 844:\t\tkho_scratch = memblock_alloc(size, PAGE_SIZE);\n 845:\t\tif (!kho_scratch) {\n 846:\t\t\tpr_err(\"Failed to reserve scratch array\\n\");\n 847:\t\t\tgoto err_disable_kho;\n 848:\t\t}\n 849:\t\n 850:\t\t/*\n 851:\t\t * Calculate the per-node sizes before reserving any scratch areas.\n 852:\t\t * memblock allocations are marked MEMBLOCK_RSRV_KERN, so calculating\n 853:\t\t * them later would count the lowmem and global scratch areas as kernel\n 854:\t\t * allocations and scale them again.\n 855:\t\t */\n 856:\t\ti = 2;\n 857:\t\tfor_each_node_state(nid, N_MEMORY)\n 858:\t\t\tkho_scratch[i++].size = scratch_size_node(nid);\n 859:\t\ti = 0;\n 860:\t\n 861:\t\t/*\n 862:\t\t * reserve scratch area in low memory for lowmem allocations in the\n 863:\t\t * next kernel\n 864:\t\t */\n 865:\t\tsize = scratch_size_lowmem;\n 866:\t\taddr = memblock_phys_alloc_range(size, SCRATCH_ALIGNMENT_BYTES, 0,\n 867:\t\t\t\t\t\t ARCH_LOW_ADDRESS_LIMIT);\n 868:\t\tif (!addr) {\n 869:\t\t\tpr_err(\"Failed to reserve lowmem scratch buffer\\n\");\n 870:\t\t\tgoto err_free_scratch_desc;\n 871:\t\t}\n 872:\t\n 873:\t\tkho_scratch[i].addr = addr;\n 874:\t\tkho_scratch[i].size = size;\n 875:\t\ti++;\n 876:\t\n 877:\t\t/* reserve large contiguous area for allocations without nid */\n 878:\t\tsize = scratch_size_global;\n 879:\t\taddr = memblock_phys_alloc(size, SCRATCH_ALIGNMENT_BYTES);\n 880:\t\tif (!addr) {\n 881:\t\t\tpr_err(\"Failed to reserve global scratch buffer\\n\");\n 882:\t\t\tgoto err_free_scratch_areas;\n 883:\t\t}\n 884:\t\n 885:\t\tkho_scratch[i].addr = addr;\n 886:\t\tkho_scratch[i].size = size;\n 887:\t\ti++;\n 888:\t\n 889:\t\t/*\n 890:\t\t * Loop over nodes that have both memory and are online. Skip\n 891:\t\t * memoryless nodes, as we can not allocate scratch areas there.\n 892:\t\t */\n 893:\t\tfor_each_node_state(nid, N_MEMORY) {\n 894:\t\t\tsize = kho_scratch[i].size;\n 895:\t\t\taddr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES,\n 896:\t\t\t\t\t\t\t0, MEMBLOCK_ALLOC_ACCESSIBLE,\n 897:\t\t\t\t\t\t\tnid, true);\n 898:\t\t\tif (!addr) {\n 899:\t\t\t\tpr_err(\"Failed to reserve nid %d scratch buffer\\n\", nid);\n 900:\t\t\t\tgoto err_free_scratch_areas;\n 901:\t\t\t}\n 902:\t\n 903:\t\t\tkho_scratch[i].addr = addr;\n 904:\t\t\tkho_scratch[i].size = size;\n 905:\t\t\ti++;\n 906:\t\t}\n 907:\t\n 908:\t\treturn;\n 909:\t\n 910:\terr_free_scratch_areas:\n 911:\t\tfor (i--; i \u003e= 0; i--)\n 912:\t\t\tmemblock_phys_free(kho_scratch[i].addr, kho_scratch[i].size);\n 913:\terr_free_scratch_desc:\n 914:\t\tmemblock_free(kho_scratch, kho_scratch_cnt * sizeof(*kho_scratch));\n 915:\terr_disable_kho:\n 916:\t\tpr_warn(\"Failed to reserve scratch area, disabling kexec handover\\n\");\n 917:\t\tkho_enable = false;\n 918:\t}\n 919:\t\n"
}

5/2 2026/09/05 11:49 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 4911
							output: 19
							thoughts: 16
						

Thoughts:
Here's a summary of my thought process:

**Tracing the Usage of `kho_reserve_scratch`**

Okay, so I need to understand the lifecycle of `kho_reserve_scratch`. It's time to dive into the codebase and see where this function or variable is actually used. My immediate goal is to locate all of its call sites. Knowing where it's invoked will provide crucial context and allow me to understand its purpose within the larger system. I'll start by doing a quick search through the code. I'm expecting this to be a straightforward process, but let's see what the search results turn up.



6/2 2026/09/05 11:49 tool grepper
0m Args:
{
  "Expression": "kho_reserve_scratch"
}

Results:
{
  "Output": "kernel/liveupdate/kexec_handover.c=806=bool kho_scratch_overlap(phys_addr_t phys, size_t size)\n--\nkernel/liveupdate/kexec_handover.c-822-/**\nkernel/liveupdate/kexec_handover.c:823: * kho_reserve_scratch - Reserve a contiguous chunk of memory for kexec\nkernel/liveupdate/kexec_handover.c-824- *\n--\nkernel/liveupdate/kexec_handover.c-830- */\nkernel/liveupdate/kexec_handover.c:831:static void __init kho_reserve_scratch(void)\nkernel/liveupdate/kexec_handover.c-832-{\n--\nkernel/liveupdate/kexec_handover.c=1951=void __init kho_memory_init(void)\n--\nkernel/liveupdate/kexec_handover.c-1955-\telse\nkernel/liveupdate/kexec_handover.c:1956:\t\tkho_reserve_scratch();\nkernel/liveupdate/kexec_handover.c-1957-}\n"
}

7/2 2026/09/05 11:49 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 5371
							output: 19
							thoughts: 16
						

Thoughts:
Here's my take on those thoughts:

**Tracing the Call Path: `kho_memory_init`**

Alright, let's dive in. My immediate thought is, "Okay, where are we initializing this `kho_memory` structure?" I need to understand the control flow, the overall architecture, and how the memory management is set up. Knowing where `kho_memory_init` is invoked is crucial for comprehending the lifecycle of the memory subsystem. I need to trace back from that initialization function to understand what's triggering it, what dependencies it has, and what state the system is in when the initialization happens. This will help me contextualize any issues or performance characteristics related to this memory management. This is the first step toward getting a solid grasp on how this particular memory component operates and how to troubleshoot it when things inevitably go wrong.



8/2 2026/09/05 11:49 tool grepper
0m Args:
{
  "Expression": "kho_memory_init"
}

Results:
{
  "Output": "include/linux/kexec_handover.h=34=int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);\ninclude/linux/kexec_handover.h-35-\ninclude/linux/kexec_handover.h:36:void kho_memory_init(void);\ninclude/linux/kexec_handover.h:37:void kho_memory_init_early(void);\ninclude/linux/kexec_handover.h-38-\n--\ninclude/linux/kexec_handover.h=115=static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys,\n--\ninclude/linux/kexec_handover.h-120-\ninclude/linux/kexec_handover.h:121:static inline void kho_memory_init(void) { }\ninclude/linux/kexec_handover.h-122-\ninclude/linux/kexec_handover.h:123:static inline void kho_memory_init_early(void) { }\ninclude/linux/kexec_handover.h-124-\n--\nkernel/liveupdate/kexec_handover.c=1909=fs_initcall(kho_init);\nkernel/liveupdate/kexec_handover.c-1910-\nkernel/liveupdate/kexec_handover.c:1911:void __init kho_memory_init_early(void)\nkernel/liveupdate/kexec_handover.c-1912-{\n--\nkernel/liveupdate/kexec_handover.c-1950-\nkernel/liveupdate/kexec_handover.c:1951:void __init kho_memory_init(void)\nkernel/liveupdate/kexec_handover.c-1952-{\n--\nmm/mm_init.c=2680=void __init mm_core_init_early(void)\nmm/mm_init.c-2681-{\nmm/mm_init.c:2682:\tkho_memory_init_early();\nmm/mm_init.c-2683-\n--\nmm/mm_init.c=2697=void __init mm_core_init(void)\n--\nmm/mm_init.c-2721-\t */\nmm/mm_init.c:2722:\tkho_memory_init();\nmm/mm_init.c-2723-\n"
}

9/2 2026/09/05 11:49 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 6207
							output: 17
							thoughts: 173
						

Thoughts:
**My Initial Thoughts on `kho_reserve_scratch`**

Okay, so `kho_reserve_scratch` is essentially the `__init` function called by `kho_memory_init()`, which itself is an `__init` function called from `mm_core_init()` during the kernel's boot process. So, initially, it sounds like we're dealing with early boot memory allocation via `memblock`. But I need to be absolutely sure. Is this *purely* a boot-time function? That's the critical question here.

Time to shift gears. Let's dig into the context. What's syzkaller testing in relation to this? And I should re-familiarize myself with what liveupdate and kexec_handover are doing as this could be a related use case.

Alright, let's take a good look at the `kernel/liveupdate/kexec_handover.c` file and understand the complete flow, because that might reveal something important. How does the live update/kexec handover process work in relation to memory? Are there runtime calls being made?

Ultimately, the money question is whether there's some kind of interaction with `kho_scratch` at runtime. Are there syscalls, ioctls, sysfs, debugfs interfaces, or even the kexec interface itself, that might be touching this reserved memory region? I need to know.

Therefore, I need to launch a comprehensive kernel-wide search for instances of `kho_scratch`. That will illuminate the true extent of its usage.



10/2 2026/09/05 11:49 tool grepper
0m Args:
{
  "Expression": "kho_scratch"
}

Results:
{
  "Output": "Documentation/admin-guide/kernel-parameters.txt=98=Kernel parameters\n--\nDocumentation/admin-guide/kernel-parameters.txt-3033-\nDocumentation/admin-guide/kernel-parameters.txt:3034:\tkho_scratch=\t[KEXEC,EARLY]\nDocumentation/admin-guide/kernel-parameters.txt-3035-\t\t\tFormat: ll[KMG],mm[KMG],nn[KMG] | nn%\n--\nDocumentation/admin-guide/mm/kho.rst=22=To use KHO, please boot the kernel with the ``kho=on`` command line\nDocumentation/admin-guide/mm/kho.rst:23:parameter. You may use ``kho_scratch`` parameter to define size of the\nDocumentation/admin-guide/mm/kho.rst:24:scratch regions. For example ``kho_scratch=16M,512M,256M`` will reserve a\nDocumentation/admin-guide/mm/kho.rst-25-16 MiB low memory scratch area, a 512 MiB global scratch region, and 256 MiB\n--\nDocumentation/core-api/kho/index.rst=16=the preserved state from pre-exec kernel to post-kexec kernel and :ref:`scratch\nDocumentation/core-api/kho/index.rst:17:memory regions \u003ckho_scratch\u003e` to ensure integrity of the preserved memory.\nDocumentation/core-api/kho/index.rst-18-\n--\nDocumentation/core-api/kho/index.rst=35=and post-kexec kernels. This ABI is defined by header files in\n--\nDocumentation/core-api/kho/index.rst-42-\nDocumentation/core-api/kho/index.rst:43:.. _kho_scratch:\nDocumentation/core-api/kho/index.rst-44-\n--\nDocumentation/core-api/kho/index.rst=58=By default, size of the scratch region is calculated based on amount of memory\nDocumentation/core-api/kho/index.rst:59:allocated during boot. The ``kho_scratch`` kernel command line option may be\nDocumentation/core-api/kho/index.rst-60-used to explicitly define size of the scratch regions.\n--\nDocumentation/core-api/kho/index.rst=65=movable pages can be located inside.\nDocumentation/core-api/kho/index.rst-66-\nDocumentation/core-api/kho/index.rst:67:After KHO kexec, we ignore the ``kho_scratch`` kernel command line option and\nDocumentation/core-api/kho/index.rst-68-instead reuse the exact same region that was originally allocated. This allows\n--\narch/x86/boot/compressed/kaslr.c=770=static bool process_kho_entries(unsigned long minimum, unsigned long image_size)\narch/x86/boot/compressed/kaslr.c-771-{\narch/x86/boot/compressed/kaslr.c:772:\tstruct kho_scratch *kho_scratch;\narch/x86/boot/compressed/kaslr.c-773-\tstruct setup_data *ptr;\n--\narch/x86/boot/compressed/kaslr.c-783-\t\t\tkho = (struct kho_data *)(unsigned long)ptr-\u003edata;\narch/x86/boot/compressed/kaslr.c:784:\t\t\tkho_scratch = (void *)(unsigned long)kho-\u003escratch_addr;\narch/x86/boot/compressed/kaslr.c:785:\t\t\tnr_areas = kho-\u003escratch_size / sizeof(*kho_scratch);\narch/x86/boot/compressed/kaslr.c-786-\t\t\tbreak;\n--\narch/x86/boot/compressed/kaslr.c-795-\tfor (i = 0; i \u003c nr_areas; i++) {\narch/x86/boot/compressed/kaslr.c:796:\t\tstruct kho_scratch *area = \u0026kho_scratch[i];\narch/x86/boot/compressed/kaslr.c-797-\t\tstruct mem_vector region = {\n--\narch/x86/kernel/e820.c=1288=__init void e820__memblock_setup(void)\n--\narch/x86/kernel/e820.c-1365-\t */\narch/x86/kernel/e820.c:1366:\tmemblock_mark_kho_scratch(0, SZ_1M);\narch/x86/kernel/e820.c-1367-\n--\narch/x86/realmode/init.c=47=void __init reserve_real_mode(void)\n--\narch/x86/realmode/init.c-68-\narch/x86/realmode/init.c:69:\tmemblock_clear_kho_scratch(0, SZ_1M);\narch/x86/realmode/init.c-70-}\n--\ndrivers/firmware/efi/efi-init.c=159=static __init void reserve_regions(void)\n--\ndrivers/firmware/efi/efi-init.c-180-\t\tfor_each_mem_region(r) {\ndrivers/firmware/efi/efi-init.c:181:\t\t\tif (!memblock_is_kho_scratch(r)) {\ndrivers/firmware/efi/efi-init.c-182-\t\t\t\tmemblock_remove(r-\u003ebase, r-\u003esize);\n--\ninclude/asm-generic/kexec_handover.h-6-\ninclude/asm-generic/kexec_handover.h:7:struct kho_scratch {\ninclude/asm-generic/kexec_handover.h-8-\tphys_addr_t addr;\n--\ninclude/linux/kexec_handover.h=39=void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,\n--\ninclude/linux/kexec_handover.h-41-\ninclude/linux/kexec_handover.h:42:bool kho_scratch_overlap(phys_addr_t phys, size_t size);\ninclude/linux/kexec_handover.h-43-\ninclude/linux/kexec_handover.h:44:static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,\ninclude/linux/kexec_handover.h-45-\t\t\t\t\t\t       enum migratetype mt)\ninclude/linux/kexec_handover.h-46-{\ninclude/linux/kexec_handover.h:47:\tif (kho_scratch_overlap(PFN_PHYS(pfn), pageblock_nr_pages \u003c\u003c PAGE_SHIFT))\ninclude/linux/kexec_handover.h-48-\t\treturn MIGRATE_CMA;\n--\ninclude/linux/kexec_handover.h=125=static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,\n--\ninclude/linux/kexec_handover.h-129-\ninclude/linux/kexec_handover.h:130:static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)\ninclude/linux/kexec_handover.h-131-{\n--\ninclude/linux/kexec_handover.h-134-\ninclude/linux/kexec_handover.h:135:static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,\ninclude/linux/kexec_handover.h-136-\t\t\t\t\t\t       enum migratetype mt)\n--\ninclude/linux/memblock.h=160=int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size);\ninclude/linux/memblock.h:161:int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size);\ninclude/linux/memblock.h:162:int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size);\ninclude/linux/memblock.h-163-\n--\ninclude/linux/memblock.h=299=static inline bool memblock_is_driver_managed(struct memblock_region *m)\n--\ninclude/linux/memblock.h-303-\ninclude/linux/memblock.h:304:static inline bool memblock_is_kho_scratch(struct memblock_region *m)\ninclude/linux/memblock.h-305-{\n--\ninclude/linux/memblock.h=614=static inline void memtest_report_meminfo(struct seq_file *m) { }\n--\ninclude/linux/memblock.h-617-#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH\ninclude/linux/memblock.h:618:void memblock_set_kho_scratch_only(void);\ninclude/linux/memblock.h:619:void memblock_clear_kho_scratch_only(void);\ninclude/linux/memblock.h-620-#else\ninclude/linux/memblock.h:621:static inline void memblock_set_kho_scratch_only(void) { }\ninclude/linux/memblock.h:622:static inline void memblock_clear_kho_scratch_only(void) { }\ninclude/linux/memblock.h-623-#endif\n--\nkernel/liveupdate/kexec_handover.c=651=static void __init *kho_get_mem_map(const void *fdt)\n--\nkernel/liveupdate/kexec_handover.c-665- */\nkernel/liveupdate/kexec_handover.c:666:struct kho_scratch *kho_scratch;\nkernel/liveupdate/kexec_handover.c:667:unsigned int kho_scratch_cnt;\nkernel/liveupdate/kexec_handover.c-668-\n--\nkernel/liveupdate/kexec_handover.c-672- *\nkernel/liveupdate/kexec_handover.c:673: * kho_scratch=N%\nkernel/liveupdate/kexec_handover.c-674- *\n--\nkernel/liveupdate/kexec_handover.c-677- *\nkernel/liveupdate/kexec_handover.c:678: * kho_scratch=l[KMG],n[KMG],m[KMG]\nkernel/liveupdate/kexec_handover.c-679- *\n--\nkernel/liveupdate/kexec_handover.c=687=static int __init kho_parse_scratch_size(char *p)\n--\nkernel/liveupdate/kexec_handover.c-752-}\nkernel/liveupdate/kexec_handover.c:753:early_param(\"kho_scratch\", kho_parse_scratch_size);\nkernel/liveupdate/kexec_handover.c-754-\n--\nkernel/liveupdate/kexec_handover.c=788=static phys_addr_t __init scratch_size_node(int nid)\n--\nkernel/liveupdate/kexec_handover.c-805-\nkernel/liveupdate/kexec_handover.c:806:bool kho_scratch_overlap(phys_addr_t phys, size_t size)\nkernel/liveupdate/kexec_handover.c-807-{\n--\nkernel/liveupdate/kexec_handover.c-810-\nkernel/liveupdate/kexec_handover.c:811:\tfor (i = 0; i \u003c kho_scratch_cnt; i++) {\nkernel/liveupdate/kexec_handover.c:812:\t\tscratch_start = kho_scratch[i].addr;\nkernel/liveupdate/kexec_handover.c:813:\t\tscratch_end = kho_scratch[i].addr + kho_scratch[i].size;\nkernel/liveupdate/kexec_handover.c-814-\n--\nkernel/liveupdate/kexec_handover.c=831=static void __init kho_reserve_scratch(void)\n--\nkernel/liveupdate/kexec_handover.c-841-\t/* FIXME: deal with node hot-plug/remove */\nkernel/liveupdate/kexec_handover.c:842:\tkho_scratch_cnt = nodes_weight(node_states[N_MEMORY]) + 2;\nkernel/liveupdate/kexec_handover.c:843:\tsize = kho_scratch_cnt * sizeof(*kho_scratch);\nkernel/liveupdate/kexec_handover.c:844:\tkho_scratch = memblock_alloc(size, PAGE_SIZE);\nkernel/liveupdate/kexec_handover.c:845:\tif (!kho_scratch) {\nkernel/liveupdate/kexec_handover.c-846-\t\tpr_err(\"Failed to reserve scratch array\\n\");\n--\nkernel/liveupdate/kexec_handover.c-857-\tfor_each_node_state(nid, N_MEMORY)\nkernel/liveupdate/kexec_handover.c:858:\t\tkho_scratch[i++].size = scratch_size_node(nid);\nkernel/liveupdate/kexec_handover.c-859-\ti = 0;\n--\nkernel/liveupdate/kexec_handover.c-872-\nkernel/liveupdate/kexec_handover.c:873:\tkho_scratch[i].addr = addr;\nkernel/liveupdate/kexec_handover.c:874:\tkho_scratch[i].size = size;\nkernel/liveupdate/kexec_handover.c-875-\ti++;\n--\nkernel/liveupdate/kexec_handover.c-884-\nkernel/liveupdate/kexec_handover.c:885:\tkho_scratch[i].addr = addr;\nkernel/liveupdate/kexec_handover.c:886:\tkho_scratch[i].size = size;\nkernel/liveupdate/kexec_handover.c-887-\ti++;\n--\nkernel/liveupdate/kexec_handover.c-893-\tfor_each_node_state(nid, N_MEMORY) {\nkernel/liveupdate/kexec_handover.c:894:\t\tsize = kho_scratch[i].size;\nkernel/liveupdate/kexec_handover.c-895-\t\taddr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES,\n--\nkernel/liveupdate/kexec_handover.c-902-\nkernel/liveupdate/kexec_handover.c:903:\t\tkho_scratch[i].addr = addr;\nkernel/liveupdate/kexec_handover.c:904:\t\tkho_scratch[i].size = size;\nkernel/liveupdate/kexec_handover.c-905-\t\ti++;\n--\nkernel/liveupdate/kexec_handover.c-911-\tfor (i--; i \u003e= 0; i--)\nkernel/liveupdate/kexec_handover.c:912:\t\tmemblock_phys_free(kho_scratch[i].addr, kho_scratch[i].size);\nkernel/liveupdate/kexec_handover.c-913-err_free_scratch_desc:\nkernel/liveupdate/kexec_handover.c:914:\tmemblock_free(kho_scratch, kho_scratch_cnt * sizeof(*kho_scratch));\nkernel/liveupdate/kexec_handover.c-915-err_disable_kho:\n--\nkernel/liveupdate/kexec_handover.c=964=static int __init kho_ext_mark_scratch(unsigned long key, void *data)\n--\nkernel/liveupdate/kexec_handover.c-970-\tif (start \u003e *prev_end) {\nkernel/liveupdate/kexec_handover.c:971:\t\terr = memblock_mark_kho_scratch(*prev_end, start - *prev_end);\nkernel/liveupdate/kexec_handover.c-972-\t\tif (err)\n--\nkernel/liveupdate/kexec_handover.c=1005=static void __init kho_extend_scratch(void)\n--\nkernel/liveupdate/kexec_handover.c-1043-\tif (prev_end \u003c memblock_end_of_DRAM())\nkernel/liveupdate/kexec_handover.c:1044:\t\terr = memblock_mark_kho_scratch(prev_end, memblock_end_of_DRAM() - prev_end);\nkernel/liveupdate/kexec_handover.c-1045-\n--\nkernel/liveupdate/kexec_handover.c=1158=int kho_preserve_folio(struct folio *folio)\n--\nkernel/liveupdate/kexec_handover.c-1164-\tif (IS_ENABLED(CONFIG_KEXEC_HANDOVER_DEBUG) \u0026\u0026\nkernel/liveupdate/kexec_handover.c:1165:\t    WARN_ON(kho_scratch_overlap(pfn \u003c\u003c PAGE_SHIFT, PAGE_SIZE \u003c\u003c order)))\nkernel/liveupdate/kexec_handover.c-1166-\t\treturn -EINVAL;\n--\nkernel/liveupdate/kexec_handover.c=1233=int kho_preserve_pages(struct page *page, unsigned long nr_pages)\n--\nkernel/liveupdate/kexec_handover.c-1242-\tif (IS_ENABLED(CONFIG_KEXEC_HANDOVER_DEBUG) \u0026\u0026\nkernel/liveupdate/kexec_handover.c:1243:\t    WARN_ON(kho_scratch_overlap(start_pfn \u003c\u003c PAGE_SHIFT,\nkernel/liveupdate/kexec_handover.c-1244-\t\t\t\t\tnr_pages \u003c\u003c PAGE_SHIFT))) {\n--\nkernel/liveupdate/kexec_handover.c=1829=static __init int kho_init(void)\n--\nkernel/liveupdate/kexec_handover.c-1868-\nkernel/liveupdate/kexec_handover.c:1869:\tfor (int i = 0; i \u003c kho_scratch_cnt; i++) {\nkernel/liveupdate/kexec_handover.c:1870:\t\tunsigned long base_pfn = PHYS_PFN(kho_scratch[i].addr);\nkernel/liveupdate/kexec_handover.c:1871:\t\tunsigned long count = kho_scratch[i].size \u003e\u003e PAGE_SHIFT;\nkernel/liveupdate/kexec_handover.c-1872-\t\tunsigned long pfn;\n--\nkernel/liveupdate/kexec_handover.c-1881-\t\t */\nkernel/liveupdate/kexec_handover.c:1882:\t\tkmemleak_ignore_phys(kho_scratch[i].addr);\nkernel/liveupdate/kexec_handover.c-1883-\t\tfor (pfn = base_pfn; pfn \u003c base_pfn + count;\n--\nkernel/liveupdate/kexec_handover.c-1899-\tkho_out.fdt = NULL;\nkernel/liveupdate/kexec_handover.c:1900:\tfor (int i = 0; i \u003c kho_scratch_cnt; i++) {\nkernel/liveupdate/kexec_handover.c:1901:\t\tvoid *start = __va(kho_scratch[i].addr);\nkernel/liveupdate/kexec_handover.c:1902:\t\tvoid *end = start + kho_scratch[i].size;\nkernel/liveupdate/kexec_handover.c-1903-\n--\nkernel/liveupdate/kexec_handover.c=1911=void __init kho_memory_init_early(void)\n--\nkernel/liveupdate/kexec_handover.c-1928-\t/*\nkernel/liveupdate/kexec_handover.c:1929:\t * kho_scratch_overlap() needs kho_scratch to be initialized. It\nkernel/liveupdate/kexec_handover.c-1930-\t * is used by free_area_init() on KHO boots, so initialize it\n--\nkernel/liveupdate/kexec_handover.c-1932-\t */\nkernel/liveupdate/kexec_handover.c:1933:\tkho_scratch = phys_to_virt(kho_in.scratch_phys);\nkernel/liveupdate/kexec_handover.c-1934-\n--\nkernel/liveupdate/kexec_handover.c=1959=void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,\n--\nkernel/liveupdate/kexec_handover.c-1961-{\nkernel/liveupdate/kexec_handover.c:1962:\tunsigned int scratch_cnt = scratch_len / sizeof(*kho_scratch);\nkernel/liveupdate/kexec_handover.c:1963:\tstruct kho_scratch *scratch = NULL;\nkernel/liveupdate/kexec_handover.c-1964-\tphys_addr_t mem_map_phys;\n--\nkernel/liveupdate/kexec_handover.c-2004-\tfor (int i = 0; i \u003c scratch_cnt; i++) {\nkernel/liveupdate/kexec_handover.c:2005:\t\tstruct kho_scratch *area = \u0026scratch[i];\nkernel/liveupdate/kexec_handover.c-2006-\t\tu64 size = area-\u003esize;\n--\nkernel/liveupdate/kexec_handover.c-2008-\t\tmemblock_add(area-\u003eaddr, size);\nkernel/liveupdate/kexec_handover.c:2009:\t\terr = memblock_mark_kho_scratch(area-\u003eaddr, size);\nkernel/liveupdate/kexec_handover.c-2010-\t\tif (err) {\n--\nkernel/liveupdate/kexec_handover.c-2026-\t */\nkernel/liveupdate/kexec_handover.c:2027:\tmemblock_set_kho_scratch_only();\nkernel/liveupdate/kexec_handover.c-2028-\n--\nkernel/liveupdate/kexec_handover.c-2030-\tkho_in.scratch_phys = scratch_phys;\nkernel/liveupdate/kexec_handover.c:2031:\tkho_scratch_cnt = scratch_cnt;\nkernel/liveupdate/kexec_handover.c-2032-\n--\nkernel/liveupdate/kexec_handover.c=2047=int kho_fill_kimage(struct kimage *image)\n--\nkernel/liveupdate/kexec_handover.c-2057-\nkernel/liveupdate/kexec_handover.c:2058:\tscratch_size = sizeof(*kho_scratch) * kho_scratch_cnt;\nkernel/liveupdate/kexec_handover.c-2059-\tscratch = (struct kexec_buf){\nkernel/liveupdate/kexec_handover.c-2060-\t\t.image = image,\nkernel/liveupdate/kexec_handover.c:2061:\t\t.buffer = kho_scratch,\nkernel/liveupdate/kexec_handover.c-2062-\t\t.bufsz = scratch_size,\n--\nkernel/liveupdate/kexec_handover.c=2077=static int kho_walk_scratch(struct kexec_buf *kbuf,\n--\nkernel/liveupdate/kexec_handover.c-2082-\nkernel/liveupdate/kexec_handover.c:2083:\tfor (i = 0; i \u003c kho_scratch_cnt; i++) {\nkernel/liveupdate/kexec_handover.c-2084-\t\tstruct resource res = {\nkernel/liveupdate/kexec_handover.c:2085:\t\t\t.start = kho_scratch[i].addr,\nkernel/liveupdate/kexec_handover.c:2086:\t\t\t.end = kho_scratch[i].addr + kho_scratch[i].size - 1,\nkernel/liveupdate/kexec_handover.c-2087-\t\t};\n--\nkernel/liveupdate/kexec_handover_debugfs.c=80=static int scratch_phys_show(struct seq_file *m, void *v)\nkernel/liveupdate/kexec_handover_debugfs.c-81-{\nkernel/liveupdate/kexec_handover_debugfs.c:82:\tfor (int i = 0; i \u003c kho_scratch_cnt; i++)\nkernel/liveupdate/kexec_handover_debugfs.c:83:\t\tseq_printf(m, \"0x%llx\\n\", kho_scratch[i].addr);\nkernel/liveupdate/kexec_handover_debugfs.c-84-\n--\nkernel/liveupdate/kexec_handover_debugfs.c=89=static int scratch_len_show(struct seq_file *m, void *v)\nkernel/liveupdate/kexec_handover_debugfs.c-90-{\nkernel/liveupdate/kexec_handover_debugfs.c:91:\tfor (int i = 0; i \u003c kho_scratch_cnt; i++)\nkernel/liveupdate/kexec_handover_debugfs.c:92:\t\tseq_printf(m, \"0x%llx\\n\", kho_scratch[i].size);\nkernel/liveupdate/kexec_handover_debugfs.c-93-\n--\nkernel/liveupdate/kexec_handover_internal.h=19=struct kho_debugfs {};\n--\nkernel/liveupdate/kexec_handover_internal.h-21-\nkernel/liveupdate/kexec_handover_internal.h:22:extern struct kho_scratch *kho_scratch;\nkernel/liveupdate/kexec_handover_internal.h:23:extern unsigned int kho_scratch_cnt;\nkernel/liveupdate/kexec_handover_internal.h-24-\n--\nmm/memblock.c=114=unsigned long long max_possible_pfn;\n--\nmm/memblock.c-117-/* When set to true, only allocate from MEMBLOCK_KHO_SCRATCH ranges */\nmm/memblock.c:118:static bool kho_scratch_only;\nmm/memblock.c-119-#else\nmm/memblock.c:120:#define kho_scratch_only false\nmm/memblock.c-121-#endif\n--\nmm/memblock.c=180=static enum memblock_flags __init_memblock choose_memblock_flags(void)\n--\nmm/memblock.c-182-\t/* skip non-scratch memory for kho early boot allocations */\nmm/memblock.c:183:\tif (kho_scratch_only)\nmm/memblock.c-184-\t\treturn MEMBLOCK_KHO_SCRATCH;\n--\nmm/memblock.c=1171=int __init_memblock memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size)\n--\nmm/memblock.c-1177-/**\nmm/memblock.c:1178: * memblock_mark_kho_scratch - Mark a memory region as MEMBLOCK_KHO_SCRATCH.\nmm/memblock.c-1179- * @base: the base phys addr of the region\n--\nmm/memblock.c-1186- */\nmm/memblock.c:1187:__init int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size)\nmm/memblock.c-1188-{\n--\nmm/memblock.c-1193-/**\nmm/memblock.c:1194: * memblock_clear_kho_scratch - Clear MEMBLOCK_KHO_SCRATCH flag for a\nmm/memblock.c-1195- * specified region.\n--\nmm/memblock.c-1200- */\nmm/memblock.c:1201:__init int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size)\nmm/memblock.c-1202-{\n--\nmm/memblock.c=1207=static bool should_skip_region(struct memblock_type *type,\n--\nmm/memblock.c-1241-\t */\nmm/memblock.c:1242:\tif ((flags \u0026 MEMBLOCK_KHO_SCRATCH) \u0026\u0026 !memblock_is_kho_scratch(m))\nmm/memblock.c-1243-\t\treturn true;\n--\nmm/memblock.c=1777=void * __init memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid)\n--\nmm/memblock.c-1817-\t */\nmm/memblock.c:1818:\tif (kho_scratch_overlap(addr, size)) {\nmm/memblock.c-1819-\t\tif (memblock_bottom_up())\n--\nmm/memblock.c=2494=void __init memblock_free_all(void)\n--\nmm/memblock.c-2500-\nmm/memblock.c:2501:\tmemblock_clear_kho_scratch_only();\nmm/memblock.c-2502-\tpages = free_low_memory_core_early();\n--\nmm/memblock.c=2579=int reserve_mem_release_by_name(const char *name)\n--\nmm/memblock.c-2599-#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH\nmm/memblock.c:2600:__init void memblock_set_kho_scratch_only(void)\nmm/memblock.c-2601-{\nmm/memblock.c:2602:\tkho_scratch_only = true;\nmm/memblock.c-2603-}\nmm/memblock.c-2604-\nmm/memblock.c:2605:__init void memblock_clear_kho_scratch_only(void)\nmm/memblock.c-2606-{\nmm/memblock.c:2607:\tkho_scratch_only = false;\nmm/memblock.c-2608-}\n--\nmm/mm_init.c=681=static __meminit void pageblock_migratetype_init_range(unsigned long pfn,\n--\nmm/mm_init.c-686-\tfor (pfn = pageblock_align(pfn); pfn \u003c end; pfn += pageblock_nr_pages) {\nmm/mm_init.c:687:\t\tenum migratetype mt = kho_scratch_migratetype(pfn, migratetype);\nmm/mm_init.c-688-\n--\nmm/mm_init.c=765=static void __meminit __init_deferred_page(unsigned long pfn, int nid)\n--\nmm/mm_init.c-776-\t\tenum migratetype mt =\nmm/mm_init.c:777:\t\t\tkho_scratch_migratetype(pfn, MIGRATE_MOVABLE);\nmm/mm_init.c-778-\t\tinit_pageblock_migratetype(pfn_to_page(pfn), mt, false);\n--\ntools/testing/memblock/internal.h=39=static inline bool __is_kernel(unsigned long addr)\n--\ntools/testing/memblock/internal.h-48-\ntools/testing/memblock/internal.h:49:static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)\ntools/testing/memblock/internal.h-50-{\n"
}

11/2 2026/09/05 11:49 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 14615
							output: 20
							thoughts: 1486
						

Thoughts:
**Unreachable Code Analysis: `kho_reserve_scratch`**

Okay, let's break this down. My initial thought was to examine `kho_reserve_scratch`, which I immediately recognized as a `static void __init` function. The `__init` attribute is a red flag, suggesting it's executed only during the kernel initialization phase. I quickly tracked the call chain: `kho_memory_init` then `kho_reserve_scratch`. Then `mm_core_init` calls `kho_memory_init` and `mm_core_init` is called by `start_kernel`. Clearly this is all during early boot.

My next immediate question was whether this function, or any part of this codepath, could be reached during runtime, especially by something like syzkaller. The answer is a resounding no. `__init` functions are part of the initial RAM disk, executed once, and their memory is freed by `free_initmem()` before userspace even begins, thus, making the functions completely inaccessible after the system is fully booted. Fuzzing would be unable to invoke `kho_reserve_scratch` via any syscall, IOCTL, virtual device, or sysfs interaction.

To confirm this, I double-checked the diff provided to ensure nothing else was modified in the commit, to eliminate any doubt. It's confined to `kernel/liveupdate/kexec_handover.c`, specifically within `kho_reserve_scratch`. I then went back and verified where `kho_reserve_scratch` is called, and found that it's only called in `kho_memory_init` and from the same file.

I considered whether this KHO early boot scratch reservation, which relies on memblock allocations (`memblock_alloc`, `memblock_phys_alloc`, etc.) before the buddy allocator is initialized, would be a factor. The conclusion remained unchanged: after boot completion, the `.init.text` section containing this function is unmapped and freed.

I then revisited the "WorthFuzzing" criteria and the core triage philosophy. The "unreachable execution paths" category specifically includes code executed only during driver teardown, physical hot-unplug, or on architectures other than the target. This made me think about whether early boot `__init` code could even be considered by syzkaller.

Ultimately, syzkaller, running in userspace within a virtualized environment, is designed to execute test programs, which translate to syscall sequences. It is, therefore, unable to reach the `__init` functions that run once during kernel boot and are freed before syzkaller even begins to run. Therefore, `kho_reserve_scratch` is not reachable during fuzzing.



12/2 2026/09/05 11:50 tool grepper
0m Args:
{
  "Expression": "config KEXEC_HANDOVER"
}

Results:
{
  "Output": "kernel/liveupdate/Kconfig=3=menu \"Live Update and Kexec HandOver\"\nkernel/liveupdate/Kconfig-4-\nkernel/liveupdate/Kconfig:5:config KEXEC_HANDOVER\nkernel/liveupdate/Kconfig-6-\tbool \"kexec handover\"\n--\nkernel/liveupdate/Kconfig-17-\nkernel/liveupdate/Kconfig:18:config KEXEC_HANDOVER_DEBUG\nkernel/liveupdate/Kconfig-19-\tbool \"Enable Kexec Handover debug checks\"\n--\nkernel/liveupdate/Kconfig-26-\nkernel/liveupdate/Kconfig:27:config KEXEC_HANDOVER_DEBUGFS\nkernel/liveupdate/Kconfig-28-\tbool \"kexec handover debugfs interface\"\n--\nkernel/liveupdate/Kconfig-37-\nkernel/liveupdate/Kconfig:38:config KEXEC_HANDOVER_ENABLE_DEFAULT\nkernel/liveupdate/Kconfig-39-\tbool \"Enable kexec handover by default\"\n"
}

13/2 2026/09/05 11:50 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 16941
							output: 33
							thoughts: 13
						

Thoughts:
Here's a summary of my thought process, as requested:

**Navigating the Kernel's Live Update Configuration**

Okay, so I need to get a handle on the live update functionality within the kernel. My initial thought is to zero in on the configuration file. Given my experience, the standard place to start looking for this type of thing would be under `kernel/`. Therefore, I'm going to head directly to `kernel/liveupdate/Kconfig`. That configuration file is the bedrock for enabling, disabling, and customizing the live update features. I need to understand what options are exposed there, what dependencies they have, and how they interact with the rest of the kernel's configuration. Hopefully, the Kconfig file will give me the high-level picture before I have to dive deeper into the code. Time to dig in and see what I can find.



14/2 2026/09/05 11:50 tool read-file
0m Args:
{
  "File": "kernel/liveupdate/Kconfig",
  "FirstLine": 1,
  "LineCount": 50
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\t\n   3:\tmenu \"Live Update and Kexec HandOver\"\n   4:\t\n   5:\tconfig KEXEC_HANDOVER\n   6:\t\tbool \"kexec handover\"\n   7:\t\tdepends on ARCH_SUPPORTS_KEXEC_HANDOVER \u0026\u0026 ARCH_SUPPORTS_KEXEC_FILE\n   8:\t\tselect MEMBLOCK_KHO_SCRATCH\n   9:\t\tselect KEXEC_FILE\n  10:\t\tselect LIBFDT\n  11:\t\tselect CMA\n  12:\t\thelp\n  13:\t\t  Allow kexec to hand over state across kernels by generating and\n  14:\t\t  passing additional metadata to the target kernel. This is useful\n  15:\t\t  to keep data or state alive across the kexec. For this to work,\n  16:\t\t  both source and target kernels need to have this option enabled.\n  17:\t\n  18:\tconfig KEXEC_HANDOVER_DEBUG\n  19:\t\tbool \"Enable Kexec Handover debug checks\"\n  20:\t\tdepends on KEXEC_HANDOVER\n  21:\t\thelp\n  22:\t\t  This option enables extra sanity checks for the Kexec Handover\n  23:\t\t  subsystem. Since, KHO performance is crucial in live update\n  24:\t\t  scenarios and the extra code might be adding overhead it is\n  25:\t\t  only optionally enabled.\n  26:\t\n  27:\tconfig KEXEC_HANDOVER_DEBUGFS\n  28:\t\tbool \"kexec handover debugfs interface\"\n  29:\t\tdefault KEXEC_HANDOVER\n  30:\t\tdepends on KEXEC_HANDOVER\n  31:\t\tselect DEBUG_FS\n  32:\t\thelp\n  33:\t\t  Allow to control kexec handover device tree via debugfs\n  34:\t\t  interface, i.e. finalize the state or aborting the finalization.\n  35:\t\t  Also, enables inspecting the KHO fdt trees with the debugfs binary\n  36:\t\t  blobs.\n  37:\t\n  38:\tconfig KEXEC_HANDOVER_ENABLE_DEFAULT\n  39:\t\tbool \"Enable kexec handover by default\"\n  40:\t\tdepends on KEXEC_HANDOVER\n  41:\t\thelp\n  42:\t\t  Enable Kexec Handover by default. This avoids the need to\n  43:\t\t  explicitly pass 'kho=on' on the kernel command line.\n  44:\t\n  45:\t\t  This is useful for systems where KHO is a prerequisite for other\n  46:\t\t  features, such as Live Update, ensuring the mechanism is always\n  47:\t\t  active.\n  48:\t\n  49:\t\t  The default behavior can still be overridden at boot time by\n  50:\t\t  passing 'kho=off'.\n"
}

15/2 2026/09/05 11:50 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 17865
							output: 114
							thoughts: 352
						

Thoughts:
**My Assessment of the Fuzzing Target**

Okay, let's break this down systematically. First, I need to confirm the scope of this patch. It looks like the modification is in `kho_reserve_scratch()`, an `__init` static function within `kernel/liveupdate/kexec_handover.c`. Its role is to calculate scratch sizes per node *before* reserving lowmem and global scratch areas. This optimization avoids treating those areas as kernel allocations when scaling per-node sizes, which makes sense.

Next, the critical question: can this function be reached and fuzzed by syzkaller during runtime? No. The `__init` attribute immediately flags it. The call chain is very clear: `kho_reserve_scratch` is invoked during early boot initialization, specifically through `start_kernel` -> `mm_core_init` -> `kho_memory_init` -> `kho_reserve_scratch`. Moreover, the memory allocated for the function is explicitly freed by `free_initmem()` before userspace even starts. Syzkaller, as we know, operates by fuzzing syscalls and user-space interfaces in a running kernel. The `.init.text` code has been executed and freed, making the target unreachable to the fuzzer.

Therefore, the `WorthFuzzing` flag must be set to false. The `FocusSymbols` and `EnableConfigs` options are irrelevant in this scenario, so they should be null or an empty list.

Just to be absolutely certain, let's quickly re-iterate: We are dealing with modifications to `kho_reserve_scratch` in `kexec_handover.c`. It is a function specifically tagged as `__init`, and it is only called during early boot, prior to user-space execution.  Syzkaller focuses on the run-time kernel state, making the code unreachable to its fuzzing process.

Alright, that's rock solid. Let's call `set-results`.



16/2 2026/09/05 11:50 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies kho_reserve_scratch(), an __init function in kernel/liveupdate/kexec_handover.c that executes exclusively during early boot memory initialization (via mm_core_init) and is freed before userspace execution. Because this code cannot be triggered at runtime by syscalls, ioctls, or user-space interfaces, it is structurally unreachable to the fuzzer.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies kho_reserve_scratch(), an __init function in kernel/liveupdate/kexec_handover.c that executes exclusively during early boot memory initialization (via mm_core_init) and is freed before userspace execution. Because this code cannot be triggered at runtime by syscalls, ioctls, or user-space interfaces, it is structurally unreachable to the fuzzer.",
  "WorthFuzzing": false
}

17/1 2026/09/05 11:50 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)