AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/01 01:31 flow patch-triage
1m Args:
null

Results:
{
  "EnableConfigs": [
    "TCP_CONG_BBR",
    "BPF_SYSCALL",
    "BPF_JIT",
    "INET"
  ],
  "FocusSymbols": [
    "tcp_tso_autosize"
  ],
  "KMSANReasoning": "The patch refactors the TCP congestion control ops interface by replacing the `min_tso_segs` callback with `tso_segs(struct sock *sk, u32 mss_now)`, updates BBR and BPF congestion control hooks, and exports `tcp_tso_autosize` as a BPF kfunc.\n\nAll modified and added functions operate on scalar integer values passed by value (`u32`, `unsigned int`, pointers to fully initialized struct `sock`). No new memory allocations, stack/heap structures, or data copies to user-space (such as `copy_to_user`, netlink attributes, or ioctl returns) are introduced or modified. There is no risk of uninitialized memory reads or information leaks to user space. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch refactors the TCP congestion control ops interface by replacing the min_tso_segs callback with a tso_segs callback, updating TCP output logic (tcp_tso_autosize, tcp_tso_segs), BBR congestion control, and BPF TCP CA struct_ops. tcp_tso_autosize is also exposed as a BPF kfunc. These functional changes alter the TCP segmentation and packet scheduling path in the core networking stack and are reachable and testable in virtualized environments.",
  "WorthFuzzing": true
}

1/1 2026/09/01 01:31 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 47feec24ae21044cf7cda2f66f6fb37454b5537b\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Sep 1 01:31:44 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/include/net/tcp.h b/include/net/tcp.h\nindex 670c20876f265..79f27ac9e963a 100644\n--- a/include/net/tcp.h\n+++ b/include/net/tcp.h\n@@ -824,6 +824,9 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);\n unsigned int tcp_current_mss(struct sock *sk);\n u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when);\n \n+u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\n+\t\t     int min_tso_segs);\n+\n /* Bound MSS / TSO packet size with the half of the window */\n static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)\n {\n@@ -1361,8 +1364,16 @@ struct tcp_congestion_ops {\n \t/* hook for packet ack accounting (optional) */\n \tvoid (*pkts_acked)(struct sock *sk, const struct ack_sample *sample);\n \n-\t/* override sysctl_tcp_min_tso_segs (optional) */\n-\tu32 (*min_tso_segs)(struct sock *sk);\n+\t/* Override tcp_tso_autosize() (optional)\n+\t *\n+\t * If provided, this callback supplies the TSO segment target count\n+\t * instead of using tcp_tso_autosize(). The returned value is\n+\t * subsequently clamped to [1, sk-\u003esk_gso_max_segs] by the caller.\n+\t *\n+\t * For the kernel callback path, mss_now originates from\n+\t * tcp_current_mss() and should never be zero.\n+\t */\n+\tu32 (*tso_segs)(struct sock *sk, u32 mss_now);\n \n \t/* new value of cwnd after loss (required) */\n \tu32  (*undo_cwnd)(struct sock *sk);\ndiff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c\nindex 791e15063237c..9deed2244c2de 100644\n--- a/net/ipv4/bpf_tcp_ca.c\n+++ b/net/ipv4/bpf_tcp_ca.c\n@@ -194,6 +194,7 @@ BTF_ID_FLAGS(func, tcp_reno_cong_avoid)\n BTF_ID_FLAGS(func, tcp_reno_undo_cwnd)\n BTF_ID_FLAGS(func, tcp_slow_start)\n BTF_ID_FLAGS(func, tcp_cong_avoid_ai)\n+BTF_ID_FLAGS(func, tcp_tso_autosize)\n BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids)\n \n static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = {\n@@ -284,7 +285,7 @@ static void bpf_tcp_ca_pkts_acked(struct sock *sk, const struct ack_sample *samp\n {\n }\n \n-static u32 bpf_tcp_ca_min_tso_segs(struct sock *sk)\n+static u32 bpf_tcp_ca_tso_segs(struct sock *sk, u32 mss_now)\n {\n \treturn 0;\n }\n@@ -320,7 +321,7 @@ static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = {\n \t.cwnd_event_tx_start = bpf_tcp_ca_cwnd_event_tx_start,\n \t.in_ack_event = bpf_tcp_ca_in_ack_event,\n \t.pkts_acked = bpf_tcp_ca_pkts_acked,\n-\t.min_tso_segs = bpf_tcp_ca_min_tso_segs,\n+\t.tso_segs = bpf_tcp_ca_tso_segs,\n \t.cong_control = bpf_tcp_ca_cong_control,\n \t.undo_cwnd = bpf_tcp_ca_undo_cwnd,\n \t.sndbuf_expand = bpf_tcp_ca_sndbuf_expand,\ndiff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c\nindex 82378a2bfd1e1..ecf11be46f382 100644\n--- a/net/ipv4/tcp_bbr.c\n+++ b/net/ipv4/tcp_bbr.c\n@@ -297,11 +297,18 @@ static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)\n }\n \n /* override sysctl_tcp_min_tso_segs */\n-__bpf_kfunc static u32 bbr_min_tso_segs(struct sock *sk)\n+static u32 bbr_min_tso_segs(struct sock *sk)\n {\n \treturn READ_ONCE(sk-\u003esk_pacing_rate) \u003c (bbr_min_tso_rate \u003e\u003e 3) ? 1 : 2;\n }\n \n+__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)\n+{\n+\tif (unlikely(!mss_now))\n+\t\treturn bbr_min_tso_segs(sk);\n+\treturn tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));\n+}\n+\n static u32 bbr_tso_segs_goal(struct sock *sk)\n {\n \tstruct tcp_sock *tp = tcp_sk(sk);\n@@ -1151,7 +1158,7 @@ static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = {\n \t.undo_cwnd\t= bbr_undo_cwnd,\n \t.cwnd_event_tx_start\t= bbr_cwnd_event_tx_start,\n \t.ssthresh\t= bbr_ssthresh,\n-\t.min_tso_segs\t= bbr_min_tso_segs,\n+\t.tso_segs\t= bbr_tso_segs,\n \t.get_info\t= bbr_get_info,\n \t.set_state\t= bbr_set_state,\n };\n@@ -1163,7 +1170,7 @@ BTF_ID_FLAGS(func, bbr_sndbuf_expand)\n BTF_ID_FLAGS(func, bbr_undo_cwnd)\n BTF_ID_FLAGS(func, bbr_cwnd_event_tx_start)\n BTF_ID_FLAGS(func, bbr_ssthresh)\n-BTF_ID_FLAGS(func, bbr_min_tso_segs)\n+BTF_ID_FLAGS(func, bbr_tso_segs)\n BTF_ID_FLAGS(func, bbr_set_state)\n BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids)\n \ndiff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c\nindex 6f4dca4a4de98..b7f2ee5e7a6b1 100644\n--- a/net/ipv4/tcp_output.c\n+++ b/net/ipv4/tcp_output.c\n@@ -2252,13 +2252,21 @@ static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,\n  * in bigger TSO bursts. We we cut the RTT-based allowance in half\n  * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance\n  * is below 1500 bytes after 6 * ~500 usec = 3ms.\n+ *\n+ * The min_tso_segs is floored to 1 to avoid surprising conversion. Also,\n+ * BPF callers may pass mss_now == 0. In that case the function returns the\n+ * sanitized min_tso_segs value and skips autosizing.\n  */\n-static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\n-\t\t\t    int min_tso_segs)\n+__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\n+\t\t\t\t int min_tso_segs)\n {\n+\tu32 min_tso = max(min_tso_segs, 1);\n \tunsigned long bytes;\n \tu32 r;\n \n+\tif (unlikely(!mss_now))\n+\t\treturn min_tso;\n+\n \tbytes = READ_ONCE(sk-\u003esk_pacing_rate) \u003e\u003e READ_ONCE(sk-\u003esk_pacing_shift);\n \n \tr = tcp_min_rtt(tcp_sk(sk)) \u003e\u003e READ_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_tso_rtt_log);\n@@ -2267,8 +2275,9 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\n \n \tbytes = min_t(unsigned long, bytes, sk-\u003esk_gso_max_size);\n \n-\treturn max_t(u32, bytes / mss_now, min_tso_segs);\n+\treturn max_t(u32, bytes / mss_now, min_tso);\n }\n+EXPORT_SYMBOL_GPL(tcp_tso_autosize);\n \n /* Return the number of segments we want in the skb we are transmitting.\n  * See if congestion control module wants to decide; otherwise, autosize.\n@@ -2276,14 +2285,13 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\n static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\n {\n \tconst struct tcp_congestion_ops *ca_ops = inet_csk(sk)-\u003eicsk_ca_ops;\n-\tu32 min_tso, tso_segs;\n-\n-\tmin_tso = ca_ops-\u003emin_tso_segs ?\n-\t\t\tca_ops-\u003emin_tso_segs(sk) :\n-\t\t\tREAD_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_min_tso_segs);\n+\tu32 tso_segs;\n \n-\ttso_segs = tcp_tso_autosize(sk, mss_now, min_tso);\n-\treturn min_t(u32, tso_segs, sk-\u003esk_gso_max_segs);\n+\ttso_segs = ca_ops-\u003etso_segs ?\n+\t\t\tca_ops-\u003etso_segs(sk, mss_now) :\n+\t\t\ttcp_tso_autosize(sk, mss_now,\n+\t\t\t\t\t READ_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_min_tso_segs));\n+\treturn clamp_t(u32, tso_segs, 1, sk-\u003esk_gso_max_segs);\n }\n \n /* Returns the portion of skb which can be sent right away */\ndiff --git a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c\nindex 0a3e9d35bf6f0..58262e4903364 100644\n--- a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c\n+++ b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c\n@@ -10,7 +10,7 @@ extern u32 bbr_sndbuf_expand(struct sock *sk) __ksym;\n extern u32 bbr_undo_cwnd(struct sock *sk) __ksym;\n extern void bbr_cwnd_event_tx_start(struct sock *sk) __ksym;\n extern u32 bbr_ssthresh(struct sock *sk) __ksym;\n-extern u32 bbr_min_tso_segs(struct sock *sk) __ksym;\n+extern u32 bbr_tso_segs(struct sock *sk, u32 mss_now) __ksym;\n extern void bbr_set_state(struct sock *sk, u8 new_state) __ksym;\n \n extern void dctcp_init(struct sock *sk) __ksym;\n@@ -90,9 +90,9 @@ u32 BPF_PROG(ssthresh, struct sock *sk)\n }\n \n SEC(\"struct_ops\")\n-u32 BPF_PROG(min_tso_segs, struct sock *sk)\n+u32 BPF_PROG(tso_segs, struct sock *sk, u32 mss_now)\n {\n-\treturn bbr_min_tso_segs(sk);\n+\treturn bbr_tso_segs(sk, mss_now);\n }\n \n SEC(\"struct_ops\")\n@@ -120,7 +120,7 @@ struct tcp_congestion_ops tcp_ca_kfunc = {\n \t.cwnd_event\t= (void *)cwnd_event,\n \t.cwnd_event_tx_start = (void *)cwnd_event_tx_start,\n \t.ssthresh\t= (void *)ssthresh,\n-\t.min_tso_segs\t= (void *)min_tso_segs,\n+\t.tso_segs\t= (void *)tso_segs,\n \t.set_state\t= (void *)set_state,\n \t.pkts_acked     = (void *)pkts_acked,\n \t.name\t\t= \"tcp_ca_kfunc\",\n"
}

2/1 2026/09/01 01:31 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "TCP_CONG_BBR",
    "BPF_SYSCALL",
    "BPF_JIT",
    "INET"
  ],
  "FocusSymbols": [
    "tcp_tso_autosize"
  ],
  "Reasoning": "The patch refactors the TCP congestion control ops interface by replacing the min_tso_segs callback with a tso_segs callback, updating TCP output logic (tcp_tso_autosize, tcp_tso_segs), BBR congestion control, and BPF TCP CA struct_ops. tcp_tso_autosize is also exposed as a BPF kfunc. These functional changes alter the TCP segmentation and packet scheduling path in the core networking stack and are reachable and testable in virtualized environments.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

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.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
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.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. 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 47feec24ae21044cf7cda2f66f6fb37454b5537b
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Sep 1 01:31:44 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 670c20876f265..79f27ac9e963a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -824,6 +824,9 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);
 unsigned int tcp_current_mss(struct sock *sk);
 u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when);
 
+u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
+		     int min_tso_segs);
+
 /* Bound MSS / TSO packet size with the half of the window */
 static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
 {
@@ -1361,8 +1364,16 @@ struct tcp_congestion_ops {
 	/* hook for packet ack accounting (optional) */
 	void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample);
 
-	/* override sysctl_tcp_min_tso_segs (optional) */
-	u32 (*min_tso_segs)(struct sock *sk);
+	/* Override tcp_tso_autosize() (optional)
+	 *
+	 * If provided, this callback supplies the TSO segment target count
+	 * instead of using tcp_tso_autosize(). The returned value is
+	 * subsequently clamped to [1, sk->sk_gso_max_segs] by the caller.
+	 *
+	 * For the kernel callback path, mss_now originates from
+	 * tcp_current_mss() and should never be zero.
+	 */
+	u32 (*tso_segs)(struct sock *sk, u32 mss_now);
 
 	/* new value of cwnd after loss (required) */
 	u32  (*undo_cwnd)(struct sock *sk);
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index 791e15063237c..9deed2244c2de 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -194,6 +194,7 @@ BTF_ID_FLAGS(func, tcp_reno_cong_avoid)
 BTF_ID_FLAGS(func, tcp_reno_undo_cwnd)
 BTF_ID_FLAGS(func, tcp_slow_start)
 BTF_ID_FLAGS(func, tcp_cong_avoid_ai)
+BTF_ID_FLAGS(func, tcp_tso_autosize)
 BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids)
 
 static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = {
@@ -284,7 +285,7 @@ static void bpf_tcp_ca_pkts_acked(struct sock *sk, const struct ack_sample *samp
 {
 }
 
-static u32 bpf_tcp_ca_min_tso_segs(struct sock *sk)
+static u32 bpf_tcp_ca_tso_segs(struct sock *sk, u32 mss_now)
 {
 	return 0;
 }
@@ -320,7 +321,7 @@ static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = {
 	.cwnd_event_tx_start = bpf_tcp_ca_cwnd_event_tx_start,
 	.in_ack_event = bpf_tcp_ca_in_ack_event,
 	.pkts_acked = bpf_tcp_ca_pkts_acked,
-	.min_tso_segs = bpf_tcp_ca_min_tso_segs,
+	.tso_segs = bpf_tcp_ca_tso_segs,
 	.cong_control = bpf_tcp_ca_cong_control,
 	.undo_cwnd = bpf_tcp_ca_undo_cwnd,
 	.sndbuf_expand = bpf_tcp_ca_sndbuf_expand,
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 82378a2bfd1e1..ecf11be46f382 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -297,11 +297,18 @@ static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)
 }
 
 /* override sysctl_tcp_min_tso_segs */
-__bpf_kfunc static u32 bbr_min_tso_segs(struct sock *sk)
+static u32 bbr_min_tso_segs(struct sock *sk)
 {
 	return READ_ONCE(sk->sk_pacing_rate) < (bbr_min_tso_rate >> 3) ? 1 : 2;
 }
 
+__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)
+{
+	if (unlikely(!mss_now))
+		return bbr_min_tso_segs(sk);
+	return tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));
+}
+
 static u32 bbr_tso_segs_goal(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -1151,7 +1158,7 @@ static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = {
 	.undo_cwnd	= bbr_undo_cwnd,
 	.cwnd_event_tx_start	= bbr_cwnd_event_tx_start,
 	.ssthresh	= bbr_ssthresh,
-	.min_tso_segs	= bbr_min_tso_segs,
+	.tso_segs	= bbr_tso_segs,
 	.get_info	= bbr_get_info,
 	.set_state	= bbr_set_state,
 };
@@ -1163,7 +1170,7 @@ BTF_ID_FLAGS(func, bbr_sndbuf_expand)
 BTF_ID_FLAGS(func, bbr_undo_cwnd)
 BTF_ID_FLAGS(func, bbr_cwnd_event_tx_start)
 BTF_ID_FLAGS(func, bbr_ssthresh)
-BTF_ID_FLAGS(func, bbr_min_tso_segs)
+BTF_ID_FLAGS(func, bbr_tso_segs)
 BTF_ID_FLAGS(func, bbr_set_state)
 BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids)
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 6f4dca4a4de98..b7f2ee5e7a6b1 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2252,13 +2252,21 @@ static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,
  * in bigger TSO bursts. We we cut the RTT-based allowance in half
  * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance
  * is below 1500 bytes after 6 * ~500 usec = 3ms.
+ *
+ * The min_tso_segs is floored to 1 to avoid surprising conversion. Also,
+ * BPF callers may pass mss_now == 0. In that case the function returns the
+ * sanitized min_tso_segs value and skips autosizing.
  */
-static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
-			    int min_tso_segs)
+__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
+				 int min_tso_segs)
 {
+	u32 min_tso = max(min_tso_segs, 1);
 	unsigned long bytes;
 	u32 r;
 
+	if (unlikely(!mss_now))
+		return min_tso;
+
 	bytes = READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift);
 
 	r = tcp_min_rtt(tcp_sk(sk)) >> READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tso_rtt_log);
@@ -2267,8 +2275,9 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
 
 	bytes = min_t(unsigned long, bytes, sk->sk_gso_max_size);
 
-	return max_t(u32, bytes / mss_now, min_tso_segs);
+	return max_t(u32, bytes / mss_now, min_tso);
 }
+EXPORT_SYMBOL_GPL(tcp_tso_autosize);
 
 /* Return the number of segments we want in the skb we are transmitting.
  * See if congestion control module wants to decide; otherwise, autosize.
@@ -2276,14 +2285,13 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
 static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)
 {
 	const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
-	u32 min_tso, tso_segs;
-
-	min_tso = ca_ops->min_tso_segs ?
-			ca_ops->min_tso_segs(sk) :
-			READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs);
+	u32 tso_segs;
 
-	tso_segs = tcp_tso_autosize(sk, mss_now, min_tso);
-	return min_t(u32, tso_segs, sk->sk_gso_max_segs);
+	tso_segs = ca_ops->tso_segs ?
+			ca_ops->tso_segs(sk, mss_now) :
+			tcp_tso_autosize(sk, mss_now,
+					 READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs));
+	return clamp_t(u32, tso_segs, 1, sk->sk_gso_max_segs);
 }
 
 /* Returns the portion of skb which can be sent right away */
diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
index 0a3e9d35bf6f0..58262e4903364 100644
--- a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
@@ -10,7 +10,7 @@ extern u32 bbr_sndbuf_expand(struct sock *sk) __ksym;
 extern u32 bbr_undo_cwnd(struct sock *sk) __ksym;
 extern void bbr_cwnd_event_tx_start(struct sock *sk) __ksym;
 extern u32 bbr_ssthresh(struct sock *sk) __ksym;
-extern u32 bbr_min_tso_segs(struct sock *sk) __ksym;
+extern u32 bbr_tso_segs(struct sock *sk, u32 mss_now) __ksym;
 extern void bbr_set_state(struct sock *sk, u8 new_state) __ksym;
 
 extern void dctcp_init(struct sock *sk) __ksym;
@@ -90,9 +90,9 @@ u32 BPF_PROG(ssthresh, struct sock *sk)
 }
 
 SEC("struct_ops")
-u32 BPF_PROG(min_tso_segs, struct sock *sk)
+u32 BPF_PROG(tso_segs, struct sock *sk, u32 mss_now)
 {
-	return bbr_min_tso_segs(sk);
+	return bbr_tso_segs(sk, mss_now);
 }
 
 SEC("struct_ops")
@@ -120,7 +120,7 @@ struct tcp_congestion_ops tcp_ca_kfunc = {
 	.cwnd_event	= (void *)cwnd_event,
 	.cwnd_event_tx_start = (void *)cwnd_event_tx_start,
 	.ssthresh	= (void *)ssthresh,
-	.min_tso_segs	= (void *)min_tso_segs,
+	.tso_segs	= (void *)tso_segs,
 	.set_state	= (void *)set_state,
 	.pkts_acked     = (void *)pkts_acked,
 	.name		= "tcp_ca_kfunc",

3/2 2026/09/01 01:31 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 5469
							output: 31
							thoughts: 301
						

Thoughts:
**Analyzing the TSO Segment Count and BPF Integration**

Okay, so it looks like they've revamped how the TSO segment count is handled within the TCP congestion control structure. Instead of a `min_tso_segs` callback, we now have a `tso_segs` callback that takes the socket (`sk`) and the current Maximum Segment Size (`mss_now`) as input and directly returns the TSO segment count. That's a pretty significant shift in the interface, and immediately I'm thinking about the implications for congestion control algorithms, especially those that are BPF-based.

Also, exporting `tcp_tso_autosize` as both a BPF kfunc and a regular symbol is interesting. That opens up some possibilities for userspace control or dynamic adjustments, which could be useful. The updates to the BPF TCP congestion control `struct_ops` and the BBR congestion control ops are expected, since there's a new interface. Now I have to look into the specifics of that.

My initial thought is to figure out if these changes are going to be worth fuzzing. I need to understand the details. The included files: `include/net/tcp.h`, `net/ipv4/bpf_tcp_ca.c`, `net/ipv4/tcp_bbr.c`, `net/ipv4/tcp_output.c`, and `tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c`. I have to dig into those files to understand the specifics of how the congestion control algorithms have been changed.

So, I’ll start by focusing on `net/ipv4/tcp_output.c` to see how it uses the new `tso_segs()` and then look at the changes to the BBR and BPF congestion control implementations. I'll probably use `grepper` or `read-file` to get a quick overview of what's been changed, as well as to look for configs and the affected functions.



4/2 2026/09/01 01:31 tool grepper
0m Args:
{
  "Expression": "tcp_tso_autosize",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/bpf_tcp_ca.c=196=BTF_ID_FLAGS(func, tcp_cong_avoid_ai)\nnet/ipv4/bpf_tcp_ca.c:197:BTF_ID_FLAGS(func, tcp_tso_autosize)\nnet/ipv4/bpf_tcp_ca.c-198-BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids)\n--\nnet/ipv4/tcp.c=957=static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,\n--\nnet/ipv4/tcp.c-965-\nnet/ipv4/tcp.c:966:\t/* Note : tcp_tso_autosize() will eventually split this later */\nnet/ipv4/tcp.c-967-\tnew_size_goal = tcp_bound_to_half_wnd(tp, sk-\u003esk_gso_max_size);\n--\nnet/ipv4/tcp_bbr.c=305=__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)\n--\nnet/ipv4/tcp_bbr.c-308-\t\treturn bbr_min_tso_segs(sk);\nnet/ipv4/tcp_bbr.c:309:\treturn tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));\nnet/ipv4/tcp_bbr.c-310-}\n--\nnet/ipv4/tcp_bbr.c=312=static u32 bbr_tso_segs_goal(struct sock *sk)\n--\nnet/ipv4/tcp_bbr.c-316-\nnet/ipv4/tcp_bbr.c:317:\t/* Sort of tcp_tso_autosize() but ignoring\nnet/ipv4/tcp_bbr.c-318-\t * driver provided sk_gso_max_size.\n--\nnet/ipv4/tcp_output.c=2234=static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,\n--\nnet/ipv4/tcp_output.c-2259- */\nnet/ipv4/tcp_output.c:2260:__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\nnet/ipv4/tcp_output.c-2261-\t\t\t\t int min_tso_segs)\n--\nnet/ipv4/tcp_output.c-2279-}\nnet/ipv4/tcp_output.c:2280:EXPORT_SYMBOL_GPL(tcp_tso_autosize);\nnet/ipv4/tcp_output.c-2281-\n--\nnet/ipv4/tcp_output.c=2285=static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\n--\nnet/ipv4/tcp_output.c-2291-\t\t\tca_ops-\u003etso_segs(sk, mss_now) :\nnet/ipv4/tcp_output.c:2292:\t\t\ttcp_tso_autosize(sk, mss_now,\nnet/ipv4/tcp_output.c-2293-\t\t\t\t\t READ_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_min_tso_segs));\n"
}

5/2 2026/09/01 01:31 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 7122
							output: 31
							thoughts: 44
						

Thoughts:
**Investigating BPF and TCP Congestion Control Dependencies**

Okay, let's dive in. I need to understand the configuration dependencies of a couple of BPF and TCP congestion control modules. My first step is to see what Kconfig options specifically relate to `bpf_tcp_ca.c` and `tcp_bbr.c`. I need to figure out which features they rely on, and what needs to be enabled to include them in a kernel build. To do that, I'll start by checking the relevant `net/ipv4/Kconfig` file. That's the logical place to start, given the nature of the modules. Hopefully, the dependencies are clearly laid out there. Time to get to it.



6/2 2026/09/01 01:31 tool grepper
0m Args:
{
  "Expression": "TCP_CONG_BBR",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/Kconfig=649=config TCP_CONG_CDG\n--\nnet/ipv4/Kconfig-665-\nnet/ipv4/Kconfig:666:config TCP_CONG_BBR\nnet/ipv4/Kconfig-667-\ttristate \"BBR TCP\"\n--\nnet/ipv4/Kconfig=681=choice\n--\nnet/ipv4/Kconfig-715-\tconfig DEFAULT_BBR\nnet/ipv4/Kconfig:716:\t\tbool \"BBR\" if TCP_CONG_BBR=y\nnet/ipv4/Kconfig-717-\n--\nnet/ipv4/Makefile=46=obj-$(CONFIG_INET_RAW_DIAG) += raw_diag.o\nnet/ipv4/Makefile:47:obj-$(CONFIG_TCP_CONG_BBR) += tcp_bbr.o\nnet/ipv4/Makefile-48-obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o\n"
}

7/2 2026/09/01 01:31 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 7611
							output: 30
							thoughts: 34
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Investigating TCP Congestion Control Instrumentation**

Alright, I need to dig deeper into where the BPF-based TCP congestion control probes are defined and configured. I've already got a good grasp, but let's be thorough. I'm thinking I should start by explicitly checking `net/ipv4/bpf_tcp_ca.c`. That should give me the core logic for the BPF-based congestion control implementation itself. Then, for the build configuration and any associated compile-time options, it's essential to look at `net/ipv4/Makefile` and `net/ipv4/Kconfig`. These will reveal how this particular module is integrated into the kernel's build system and what controls its inclusion or exclusion based on user configuration. I need to be sure I understand the full picture, including any dependencies or conditional compilation aspects.



8/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "bpf_tcp_ca",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/Makefile=71=ifeq ($(CONFIG_BPF_JIT),y)\nnet/ipv4/Makefile:72:obj-$(CONFIG_BPF_SYSCALL) += bpf_tcp_ca.o\nnet/ipv4/Makefile-73-endif\n--\nnet/ipv4/bpf_tcp_ca.c=19=static const struct btf_type *tcp_congestion_ops_type;\nnet/ipv4/bpf_tcp_ca.c-20-\nnet/ipv4/bpf_tcp_ca.c:21:static int bpf_tcp_ca_init(struct btf *btf)\nnet/ipv4/bpf_tcp_ca.c-22-{\n--\nnet/ipv4/bpf_tcp_ca.c-43-\nnet/ipv4/bpf_tcp_ca.c:44:static bool bpf_tcp_ca_is_valid_access(int off, int size,\nnet/ipv4/bpf_tcp_ca.c-45-\t\t\t\t       enum bpf_access_type type,\n--\nnet/ipv4/bpf_tcp_ca.c-60-\nnet/ipv4/bpf_tcp_ca.c:61:static int bpf_tcp_ca_btf_struct_access(struct bpf_verifier_log *log,\nnet/ipv4/bpf_tcp_ca.c-62-\t\t\t\t\tconst struct bpf_reg_state *reg,\n--\nnet/ipv4/bpf_tcp_ca.c=121=BPF_CALL_2(bpf_tcp_send_ack, struct tcp_sock *, tp, u32, rcv_nxt)\nnet/ipv4/bpf_tcp_ca.c-122-{\nnet/ipv4/bpf_tcp_ca.c:123:\t/* bpf_tcp_ca prog cannot have NULL tp */\nnet/ipv4/bpf_tcp_ca.c-124-\t__tcp_send_ack((struct sock *)tp, rcv_nxt, 0);\n--\nnet/ipv4/bpf_tcp_ca.c=151=static const struct bpf_func_proto *\nnet/ipv4/bpf_tcp_ca.c:152:bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id,\nnet/ipv4/bpf_tcp_ca.c-153-\t\t\t  const struct bpf_prog *prog)\n--\nnet/ipv4/bpf_tcp_ca.c-190-\nnet/ipv4/bpf_tcp_ca.c:191:BTF_KFUNCS_START(bpf_tcp_ca_check_kfunc_ids)\nnet/ipv4/bpf_tcp_ca.c-192-BTF_ID_FLAGS(func, tcp_reno_ssthresh)\n--\nnet/ipv4/bpf_tcp_ca.c=197=BTF_ID_FLAGS(func, tcp_tso_autosize)\nnet/ipv4/bpf_tcp_ca.c:198:BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids)\nnet/ipv4/bpf_tcp_ca.c-199-\nnet/ipv4/bpf_tcp_ca.c:200:static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = {\nnet/ipv4/bpf_tcp_ca.c-201-\t.owner = THIS_MODULE,\nnet/ipv4/bpf_tcp_ca.c:202:\t.set   = \u0026bpf_tcp_ca_check_kfunc_ids,\nnet/ipv4/bpf_tcp_ca.c-203-};\nnet/ipv4/bpf_tcp_ca.c-204-\nnet/ipv4/bpf_tcp_ca.c:205:static const struct bpf_verifier_ops bpf_tcp_ca_verifier_ops = {\nnet/ipv4/bpf_tcp_ca.c:206:\t.get_func_proto\t\t= bpf_tcp_ca_get_func_proto,\nnet/ipv4/bpf_tcp_ca.c:207:\t.is_valid_access\t= bpf_tcp_ca_is_valid_access,\nnet/ipv4/bpf_tcp_ca.c:208:\t.btf_struct_access\t= bpf_tcp_ca_btf_struct_access,\nnet/ipv4/bpf_tcp_ca.c-209-};\nnet/ipv4/bpf_tcp_ca.c-210-\nnet/ipv4/bpf_tcp_ca.c:211:static int bpf_tcp_ca_init_member(const struct btf_type *t,\nnet/ipv4/bpf_tcp_ca.c-212-\t\t\t\t  const struct btf_member *member,\n--\nnet/ipv4/bpf_tcp_ca.c-238-\nnet/ipv4/bpf_tcp_ca.c:239:static int bpf_tcp_ca_reg(void *kdata, struct bpf_link *link)\nnet/ipv4/bpf_tcp_ca.c-240-{\n--\nnet/ipv4/bpf_tcp_ca.c-243-\nnet/ipv4/bpf_tcp_ca.c:244:static void bpf_tcp_ca_unreg(void *kdata, struct bpf_link *link)\nnet/ipv4/bpf_tcp_ca.c-245-{\n--\nnet/ipv4/bpf_tcp_ca.c-248-\nnet/ipv4/bpf_tcp_ca.c:249:static int bpf_tcp_ca_update(void *kdata, void *old_kdata, struct bpf_link *link)\nnet/ipv4/bpf_tcp_ca.c-250-{\n--\nnet/ipv4/bpf_tcp_ca.c-253-\nnet/ipv4/bpf_tcp_ca.c:254:static int bpf_tcp_ca_validate(void *kdata)\nnet/ipv4/bpf_tcp_ca.c-255-{\n--\nnet/ipv4/bpf_tcp_ca.c-258-\nnet/ipv4/bpf_tcp_ca.c:259:static u32 bpf_tcp_ca_ssthresh(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-260-{\n--\nnet/ipv4/bpf_tcp_ca.c-263-\nnet/ipv4/bpf_tcp_ca.c:264:static void bpf_tcp_ca_cong_avoid(struct sock *sk, u32 ack, u32 acked)\nnet/ipv4/bpf_tcp_ca.c-265-{\n--\nnet/ipv4/bpf_tcp_ca.c-267-\nnet/ipv4/bpf_tcp_ca.c:268:static void bpf_tcp_ca_set_state(struct sock *sk, u8 new_state)\nnet/ipv4/bpf_tcp_ca.c-269-{\n--\nnet/ipv4/bpf_tcp_ca.c-271-\nnet/ipv4/bpf_tcp_ca.c:272:static void bpf_tcp_ca_cwnd_event(struct sock *sk, enum tcp_ca_event ev)\nnet/ipv4/bpf_tcp_ca.c-273-{\n--\nnet/ipv4/bpf_tcp_ca.c-275-\nnet/ipv4/bpf_tcp_ca.c:276:static void bpf_tcp_ca_cwnd_event_tx_start(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-277-{\n--\nnet/ipv4/bpf_tcp_ca.c-279-\nnet/ipv4/bpf_tcp_ca.c:280:static void bpf_tcp_ca_in_ack_event(struct sock *sk, u32 flags)\nnet/ipv4/bpf_tcp_ca.c-281-{\n--\nnet/ipv4/bpf_tcp_ca.c-283-\nnet/ipv4/bpf_tcp_ca.c:284:static void bpf_tcp_ca_pkts_acked(struct sock *sk, const struct ack_sample *sample)\nnet/ipv4/bpf_tcp_ca.c-285-{\n--\nnet/ipv4/bpf_tcp_ca.c-287-\nnet/ipv4/bpf_tcp_ca.c:288:static u32 bpf_tcp_ca_tso_segs(struct sock *sk, u32 mss_now)\nnet/ipv4/bpf_tcp_ca.c-289-{\n--\nnet/ipv4/bpf_tcp_ca.c-292-\nnet/ipv4/bpf_tcp_ca.c:293:static void bpf_tcp_ca_cong_control(struct sock *sk, u32 ack, int flag,\nnet/ipv4/bpf_tcp_ca.c-294-\t\t\t\t    const struct rate_sample *rs)\n--\nnet/ipv4/bpf_tcp_ca.c-297-\nnet/ipv4/bpf_tcp_ca.c:298:static u32 bpf_tcp_ca_undo_cwnd(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-299-{\n--\nnet/ipv4/bpf_tcp_ca.c-302-\nnet/ipv4/bpf_tcp_ca.c:303:static u32 bpf_tcp_ca_sndbuf_expand(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-304-{\n--\nnet/ipv4/bpf_tcp_ca.c-307-\nnet/ipv4/bpf_tcp_ca.c:308:static void __bpf_tcp_ca_init(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-309-{\n--\nnet/ipv4/bpf_tcp_ca.c-311-\nnet/ipv4/bpf_tcp_ca.c:312:static void __bpf_tcp_ca_release(struct sock *sk)\nnet/ipv4/bpf_tcp_ca.c-313-{\n--\nnet/ipv4/bpf_tcp_ca.c=316=static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = {\nnet/ipv4/bpf_tcp_ca.c:317:\t.ssthresh = bpf_tcp_ca_ssthresh,\nnet/ipv4/bpf_tcp_ca.c:318:\t.cong_avoid = bpf_tcp_ca_cong_avoid,\nnet/ipv4/bpf_tcp_ca.c:319:\t.set_state = bpf_tcp_ca_set_state,\nnet/ipv4/bpf_tcp_ca.c:320:\t.cwnd_event = bpf_tcp_ca_cwnd_event,\nnet/ipv4/bpf_tcp_ca.c:321:\t.cwnd_event_tx_start = bpf_tcp_ca_cwnd_event_tx_start,\nnet/ipv4/bpf_tcp_ca.c:322:\t.in_ack_event = bpf_tcp_ca_in_ack_event,\nnet/ipv4/bpf_tcp_ca.c:323:\t.pkts_acked = bpf_tcp_ca_pkts_acked,\nnet/ipv4/bpf_tcp_ca.c:324:\t.tso_segs = bpf_tcp_ca_tso_segs,\nnet/ipv4/bpf_tcp_ca.c:325:\t.cong_control = bpf_tcp_ca_cong_control,\nnet/ipv4/bpf_tcp_ca.c:326:\t.undo_cwnd = bpf_tcp_ca_undo_cwnd,\nnet/ipv4/bpf_tcp_ca.c:327:\t.sndbuf_expand = bpf_tcp_ca_sndbuf_expand,\nnet/ipv4/bpf_tcp_ca.c-328-\nnet/ipv4/bpf_tcp_ca.c:329:\t.init = __bpf_tcp_ca_init,\nnet/ipv4/bpf_tcp_ca.c:330:\t.release = __bpf_tcp_ca_release,\nnet/ipv4/bpf_tcp_ca.c-331-};\n--\nnet/ipv4/bpf_tcp_ca.c=333=static struct bpf_struct_ops bpf_tcp_congestion_ops = {\nnet/ipv4/bpf_tcp_ca.c:334:\t.verifier_ops = \u0026bpf_tcp_ca_verifier_ops,\nnet/ipv4/bpf_tcp_ca.c:335:\t.reg = bpf_tcp_ca_reg,\nnet/ipv4/bpf_tcp_ca.c:336:\t.unreg = bpf_tcp_ca_unreg,\nnet/ipv4/bpf_tcp_ca.c:337:\t.update = bpf_tcp_ca_update,\nnet/ipv4/bpf_tcp_ca.c:338:\t.init_member = bpf_tcp_ca_init_member,\nnet/ipv4/bpf_tcp_ca.c:339:\t.init = bpf_tcp_ca_init,\nnet/ipv4/bpf_tcp_ca.c:340:\t.validate = bpf_tcp_ca_validate,\nnet/ipv4/bpf_tcp_ca.c-341-\t.name = \"tcp_congestion_ops\",\n--\nnet/ipv4/bpf_tcp_ca.c-345-\nnet/ipv4/bpf_tcp_ca.c:346:static int __init bpf_tcp_ca_kfunc_init(void)\nnet/ipv4/bpf_tcp_ca.c-347-{\n--\nnet/ipv4/bpf_tcp_ca.c-349-\nnet/ipv4/bpf_tcp_ca.c:350:\tret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, \u0026bpf_tcp_ca_kfunc_set);\nnet/ipv4/bpf_tcp_ca.c-351-\tret = ret ?: register_bpf_struct_ops(\u0026bpf_tcp_congestion_ops, tcp_congestion_ops);\n--\nnet/ipv4/bpf_tcp_ca.c-354-}\nnet/ipv4/bpf_tcp_ca.c:355:late_initcall(bpf_tcp_ca_kfunc_init);\n"
}

9/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 11654
							output: 31
							thoughts: 32
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating TCP TSO Segment Size Determination**

Alright, time to dig into the TCP output path. I want to trace the logic surrounding `tcp_tso_segs` and understand how it interacts with `tcp_tso_autosize`. My immediate goal is to map out where `tcp_tso_autosize` is actually *used* within the larger TCP output process. Where are the decisions being made based on this value? I need to understand how it influences the number of segments we end up with. This likely involves diving into the TSO (TCP Segmentation Offload) code, which could mean looking at how the hardware interfaces with the software segmentation, too. I suspect `tcp_tso_segs` probably holds a calculated value, perhaps the maximum number of segments the NIC can handle efficiently, or maybe even the *actual* number after considerations of MTU, header sizes, and MSS. Ultimately, I'm trying to optimize TCP performance, so a deep understanding of this interaction is crucial. This will help me diagnose throughput bottlenecks and fine-tune parameters for optimal transfer characteristics.



10/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "tcp_tso_segs",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/tcp_output.c=2280=EXPORT_SYMBOL_GPL(tcp_tso_autosize);\n--\nnet/ipv4/tcp_output.c-2284- */\nnet/ipv4/tcp_output.c:2285:static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\nnet/ipv4/tcp_output.c-2286-{\n--\nnet/ipv4/tcp_output.c=2972=static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,\n--\nnet/ipv4/tcp_output.c-2999-\nnet/ipv4/tcp_output.c:3000:\tmax_segs = tcp_tso_segs(sk, mss_now);\nnet/ipv4/tcp_output.c-3001-\twhile ((skb = tcp_send_head(sk))) {\n--\nnet/ipv4/tcp_output.c=3733=void tcp_xmit_retransmit_queue(struct sock *sk)\n--\nnet/ipv4/tcp_output.c-3746-\tskb = tp-\u003eretransmit_skb_hint ?: rtx_head;\nnet/ipv4/tcp_output.c:3747:\tmax_segs = tcp_tso_segs(sk, tcp_current_mss(sk));\nnet/ipv4/tcp_output.c-3748-\tskb_rbtree_walk_from(skb) {\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 12368
							output: 31
							thoughts: 27
						

Thoughts:
Okay, here's my summary, presented as a stream of thought:

**Exploring Congestion Control Algorithm Space**

Alright, time to dive into this problem. I need to understand the landscape of congestion control algorithms better, specifically in relation to this `min_tso_segs` variable. I'm wondering if any of the other algorithms out there, beyond the ones I'm immediately familiar with, explicitly dealt with something like this? Did they have a similar parameter, or were they subtly affected by the number of segments used in TSO without explicitly naming a tuning parameter? That's the real question. Let's see what the research says... I need a more comprehensive view here. Time to start digging into the literature and see what emerges.



12/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "min_tso_segs",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/sysctl_net_ipv4.c=627=static const struct ctl_table ipv4_net_table[] = {\n--\nnet/ipv4/sysctl_net_ipv4.c-1393-\t{\nnet/ipv4/sysctl_net_ipv4.c:1394:\t\t.procname\t= \"tcp_min_tso_segs\",\nnet/ipv4/sysctl_net_ipv4.c:1395:\t\t.data\t\t= \u0026init_net.ipv4.sysctl_tcp_min_tso_segs,\nnet/ipv4/sysctl_net_ipv4.c-1396-\t\t.maxlen\t\t= sizeof(u8),\n--\nnet/ipv4/tcp_bbr.c=287=static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)\n--\nnet/ipv4/tcp_bbr.c-298-\nnet/ipv4/tcp_bbr.c:299:/* override sysctl_tcp_min_tso_segs */\nnet/ipv4/tcp_bbr.c:300:static u32 bbr_min_tso_segs(struct sock *sk)\nnet/ipv4/tcp_bbr.c-301-{\n--\nnet/ipv4/tcp_bbr.c=305=__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)\n--\nnet/ipv4/tcp_bbr.c-307-\tif (unlikely(!mss_now))\nnet/ipv4/tcp_bbr.c:308:\t\treturn bbr_min_tso_segs(sk);\nnet/ipv4/tcp_bbr.c:309:\treturn tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));\nnet/ipv4/tcp_bbr.c-310-}\n--\nnet/ipv4/tcp_bbr.c=312=static u32 bbr_tso_segs_goal(struct sock *sk)\n--\nnet/ipv4/tcp_bbr.c-322-\t\t      GSO_LEGACY_MAX_SIZE - 1 - MAX_TCP_HEADER);\nnet/ipv4/tcp_bbr.c:323:\tsegs = max_t(u32, bytes / tp-\u003emss_cache, bbr_min_tso_segs(sk));\nnet/ipv4/tcp_bbr.c-324-\n--\nnet/ipv4/tcp_ipv4.c=3438=static int __net_init tcp_sk_init(struct net *net)\n--\nnet/ipv4/tcp_ipv4.c-3495-\nnet/ipv4/tcp_ipv4.c:3496:\tnet-\u003eipv4.sysctl_tcp_min_tso_segs = 2;\nnet/ipv4/tcp_ipv4.c-3497-\tnet-\u003eipv4.sysctl_tcp_tso_rtt_log = 9;  /* 2^9 = 512 usec */\n--\nnet/ipv4/tcp_output.c=2234=static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,\n--\nnet/ipv4/tcp_output.c-2255- *\nnet/ipv4/tcp_output.c:2256: * The min_tso_segs is floored to 1 to avoid surprising conversion. Also,\nnet/ipv4/tcp_output.c-2257- * BPF callers may pass mss_now == 0. In that case the function returns the\nnet/ipv4/tcp_output.c:2258: * sanitized min_tso_segs value and skips autosizing.\nnet/ipv4/tcp_output.c-2259- */\nnet/ipv4/tcp_output.c=2260=__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\nnet/ipv4/tcp_output.c:2261:\t\t\t\t int min_tso_segs)\nnet/ipv4/tcp_output.c-2262-{\nnet/ipv4/tcp_output.c:2263:\tu32 min_tso = max(min_tso_segs, 1);\nnet/ipv4/tcp_output.c-2264-\tunsigned long bytes;\n--\nnet/ipv4/tcp_output.c=2285=static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\n--\nnet/ipv4/tcp_output.c-2292-\t\t\ttcp_tso_autosize(sk, mss_now,\nnet/ipv4/tcp_output.c:2293:\t\t\t\t\t READ_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_min_tso_segs));\nnet/ipv4/tcp_output.c-2294-\treturn clamp_t(u32, tso_segs, 1, sk-\u003esk_gso_max_segs);\n"
}

13/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 13903
							output: 30
							thoughts: 771
						

Thoughts:
**Fuzzing Feasibility Analysis: TSO Segment Target Count in TCP Congestion Control**

Okay, let's break this down. We've got changes related to how Congestion Control (CA) algorithms, including BBR and those using BPF struct_ops, specify the target count for TSO segments via `tso_segs` in `struct tcp_congestion_ops`. Notably, `tcp_tso_autosize` has been modified and exported as a kfunc and GPL symbol. This hits TCP output logic and the BPF TCP CA mechanism and BBR. The question is, is this a good candidate for fuzzing?

Let's run through the checklist: No changes to documentation, Kconfig, or comments, so it's actual C code. Not a purely decorative change, definitely functional. No numeric constants or macros. It *is* reachable in virtualized environments like QEMU or GCE because it's core networking, TCP, and BPF. And it's not vendor-specific or driver teardown. So, WorthFuzzing = True.

Now, for `FocusSymbols`. We need to identify the important entry points. `tcp_tso_autosize` is a non-static, exported function (kfunc). `bbr_tso_segs` is static but registered as a kfunc, while `bpf_tcp_ca_tso_segs` is also static. Specifically, `tcp_tso_autosize` looks interesting because it's `__bpf_kfunc u32 tcp_tso_autosize(...)` and `EXPORT_SYMBOL_GPL(tcp_tso_autosize)`. This makes it a great candidate. Other symbols include:
- `tcp_tso_autosize`
- `bpf_tcp_ca_tso_segs` (static)
- `bbr_tso_segs` (static, kfunc)
- `tcp_tso_segs` (static)

Based on the rules, `tcp_tso_autosize` is the clear winner for `FocusSymbols`, as it's non-static, exported, and defined in `net/ipv4/tcp_output.c`, so it's unlikely to be inlined.

Finally, for `EnableConfigs`, we need to determine the necessary kernel configurations. Clearly, `INET` (or `NET`) for TCP/IPv4, `TCP_CONG_BBR` for BBR support, and `BPF_SYSCALL` and `BPF_JIT` for BPF TCP CA/struct_ops are all essential. We should double-check the Kconfig dependencies for `bpf_tcp_ca.o` and `tcp_bbr.o` just to be absolutely sure.



14/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "BPF_SYSCALL",
  "PathPrefix": "net/ipv4"
}

Results:
{
  "Output": "net/ipv4/Makefile=63=obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o\nnet/ipv4/Makefile:64:obj-$(CONFIG_BPF_SYSCALL) += udp_bpf.o\nnet/ipv4/Makefile-65-obj-$(CONFIG_NETLABEL) += cipso_ipv4.o\n--\nnet/ipv4/Makefile=71=ifeq ($(CONFIG_BPF_JIT),y)\nnet/ipv4/Makefile:72:obj-$(CONFIG_BPF_SYSCALL) += bpf_tcp_ca.o\nnet/ipv4/Makefile-73-endif\n--\nnet/ipv4/tcp_bpf.c=178=EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir);\nnet/ipv4/tcp_bpf.c-179-\nnet/ipv4/tcp_bpf.c:180:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/tcp_bpf.c-181-static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,\n--\nnet/ipv4/tcp_bpf.c=769=void tcp_bpf_clone(const struct sock *sk, struct sock *newsk)\n--\nnet/ipv4/tcp_bpf.c-775-}\nnet/ipv4/tcp_bpf.c:776:#endif /* CONFIG_BPF_SYSCALL */\n--\nnet/ipv4/tcp_ipv4.c=2855=static int tcp4_seq_show(struct seq_file *seq, void *v)\n--\nnet/ipv4/tcp_ipv4.c-2879-\nnet/ipv4/tcp_ipv4.c:2880:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/tcp_ipv4.c-2881-union bpf_tcp_iter_batch_item {\n--\nnet/ipv4/tcp_ipv4.c=3293=static unsigned short seq_file_family(const struct seq_file *seq)\n--\nnet/ipv4/tcp_ipv4.c-3296-\nnet/ipv4/tcp_ipv4.c:3297:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/tcp_ipv4.c-3298-\t/* Iterated from bpf_iter.  Let the bpf prog to filter instead. */\n--\nnet/ipv4/tcp_ipv4.c=3348=struct proto tcp_prot = {\n--\nnet/ipv4/tcp_ipv4.c-3372-\t.put_port\t\t= inet_put_port,\nnet/ipv4/tcp_ipv4.c:3373:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/tcp_ipv4.c-3374-\t.psock_update_sk_prot\t= tcp_bpf_update_proto,\n--\nnet/ipv4/tcp_ipv4.c=3571=static struct pernet_operations __net_initdata tcp_sk_ops = {\n--\nnet/ipv4/tcp_ipv4.c-3576-\nnet/ipv4/tcp_ipv4.c:3577:#if defined(CONFIG_BPF_SYSCALL) \u0026\u0026 defined(CONFIG_PROC_FS)\nnet/ipv4/tcp_ipv4.c-3578-DEFINE_BPF_ITER_FUNC(tcp, struct bpf_iter_meta *meta,\n--\nnet/ipv4/tcp_ipv4.c=3650=void __init tcp_v4_init(void)\n--\nnet/ipv4/tcp_ipv4.c-3674-\nnet/ipv4/tcp_ipv4.c:3675:#if defined(CONFIG_BPF_SYSCALL) \u0026\u0026 defined(CONFIG_PROC_FS)\nnet/ipv4/tcp_ipv4.c-3676-\tbpf_iter_register();\n--\nnet/ipv4/udp.c=3132=struct proto udp_prot = {\n--\nnet/ipv4/udp.c-3152-\t.put_port\t\t= udp_lib_unhash,\nnet/ipv4/udp.c:3153:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/udp.c-3154-\t.psock_update_sk_prot\t= udp_bpf_update_proto,\n--\nnet/ipv4/udp.c=3171=static bool seq_sk_match(struct seq_file *seq, const struct sock *sk)\n--\nnet/ipv4/udp.c-3179-\nnet/ipv4/udp.c:3180:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/udp.c-3181-static const struct seq_operations bpf_iter_udp_seq_ops;\n--\nnet/ipv4/udp.c=3297=static int udp4_seq_show(struct seq_file *seq, void *v)\n--\nnet/ipv4/udp.c-3312-\nnet/ipv4/udp.c:3313:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/udp.c-3314-struct bpf_iter__udp {\n--\nnet/ipv4/udp.c=3586=static unsigned short seq_file_family(const struct seq_file *seq)\n--\nnet/ipv4/udp.c-3589-\nnet/ipv4/udp.c:3590:#ifdef CONFIG_BPF_SYSCALL\nnet/ipv4/udp.c-3591-\t/* BPF iterator: bpf programs to filter sockets. */\n--\nnet/ipv4/udp.c=3814=static struct pernet_operations __net_initdata udp_sysctl_ops = {\n--\nnet/ipv4/udp.c-3818-\nnet/ipv4/udp.c:3819:#if defined(CONFIG_BPF_SYSCALL) \u0026\u0026 defined(CONFIG_PROC_FS)\nnet/ipv4/udp.c-3820-DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta,\n--\nnet/ipv4/udp.c=3897=void __init udp_init(void)\n--\nnet/ipv4/udp.c-3910-\nnet/ipv4/udp.c:3911:#if defined(CONFIG_BPF_SYSCALL) \u0026\u0026 defined(CONFIG_PROC_FS)\nnet/ipv4/udp.c-3912-\tbpf_iter_register();\n"
}

15/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 16959
							output: 35
							thoughts: 28
						

Thoughts:
Okay, here's my attempt at summarizing those thoughts from a first-person, expert perspective, aiming for a fulsome rendering:

**Deep Dive on Kernel Configuration: BBR and BPF**

Alright, time to get my hands dirty. I need to quickly assess the kernel's current configuration to understand the landscape before diving into specific issues. My initial thought is to zero in on a few crucial Kconfig options: `TCP_CONG_BBR` and anything related to `BPF_SYSCALL` and `BPF_JIT`.

`TCP_CONG_BBR`, that's the primary interest. Is BBR enabled? Is it even available? This dictates a lot of my further investigation if BBR is in use or planned for. I need to confirm if it’s supported and how it's currently configured. If it's *not* enabled, that's a whole other thread of inquiry to explore the reasoning. Perhaps it was intentionally disabled due to compatibility, testing, or performance concerns? Or maybe it's just simply overlooked.

Next up are the BPF-related options. This is critical because BPF (Berkeley Packet Filter) can offer some of the most dynamic and sophisticated network performance analysis and manipulation capabilities. I'm keen to determine whether BPF is fully integrated with the system. Checking on `BPF_SYSCALL` and `BPF_JIT` ensures that the user-space programs can leverage the BPF functionality effectively, and that Just-In-Time (JIT) compilation is also available. Are we getting the full potential from BPF? Or, is it restricted to a safer, more interpretive mode? And if it's disabled, that significantly limits the possibilities for advanced tracing, networking programmability, and eBPF.

Essentially, I want to take a quick pulse of the situation. This initial Kconfig check is my compass. It helps point me in the right direction, focusing on those features that will either enable or constrain my subsequent diagnostics and optimizations. This is the starting point for really digging into network performance and application behavior. It's a quick triage step that helps me prioritize my deeper analysis.



16/2 2026/09/01 01:32 tool read-file
0m Args:
{
  "File": "net/ipv4/Kconfig",
  "FirstLine": 660,
  "LineCount": 40
}

Results:
{
  "Contents": " 660:\t\n 661:\t\t  For further details see:\n 662:\t\t    D.A. Hayes and G. Armitage. \"Revisiting TCP congestion control using\n 663:\t\t    delay gradients.\" In Networking 2011. Preprint:\n 664:\t\t    http://caia.swin.edu.au/cv/dahayes/content/networking2011-cdg-preprint.pdf\n 665:\t\n 666:\tconfig TCP_CONG_BBR\n 667:\t\ttristate \"BBR TCP\"\n 668:\t\tdefault n\n 669:\t\thelp\n 670:\t\n 671:\t\t  BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to\n 672:\t\t  maximize network utilization and minimize queues. It builds an explicit\n 673:\t\t  model of the bottleneck delivery rate and path round-trip propagation\n 674:\t\t  delay. It tolerates packet loss and delay unrelated to congestion. It\n 675:\t\t  can operate over LAN, WAN, cellular, wifi, or cable modem links. It can\n 676:\t\t  coexist with flows that use loss-based congestion control, and can\n 677:\t\t  operate with shallow buffers, deep buffers, bufferbloat, policers, or\n 678:\t\t  AQM schemes that do not provide a delay signal. It requires the fq\n 679:\t\t  (\"Fair Queue\") pacing packet scheduler.\n 680:\t\n 681:\tchoice\n 682:\t\tprompt \"Default TCP congestion control\"\n 683:\t\tdefault DEFAULT_CUBIC\n 684:\t\thelp\n 685:\t\t  Select the TCP congestion control that will be used by default\n 686:\t\t  for all connections.\n 687:\t\n 688:\t\tconfig DEFAULT_BIC\n 689:\t\t\tbool \"Bic\" if TCP_CONG_BIC=y\n 690:\t\n 691:\t\tconfig DEFAULT_CUBIC\n 692:\t\t\tbool \"Cubic\" if TCP_CONG_CUBIC=y\n 693:\t\n 694:\t\tconfig DEFAULT_HTCP\n 695:\t\t\tbool \"Htcp\" if TCP_CONG_HTCP=y\n 696:\t\n 697:\t\tconfig DEFAULT_HYBLA\n 698:\t\t\tbool \"Hybla\" if TCP_CONG_HYBLA=y\n 699:\t\n"
}

17/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 18110
							output: 35
							thoughts: 105
						

Thoughts:
**Investigating BPF and TCP Congestion Control Configuration Dependencies**

Okay, let's dive into this kernel configuration puzzle. My initial thought is to determine the necessity and "standard-ness" of `CONFIG_INET`. I suspect it's fundamental, but let's confirm. Next, I need to verify which of the potentially related configurations—`INET`, `TCP_CONG_BBR`, `BPF_SYSCALL`, and `BPF_JIT`—are either required or highly recommended for the functionality I'm after, particularly regarding BPF-based TCP Congestion Algorithms. I should also cast a wider net: are there *other* crucial configs I'm overlooking for BPF's struct_ops or for supporting `BPF_TCP_CA`?

Essentially, I need to methodically check these configurations to ensure a stable and performant integration. My immediate next step is to search the kernel source, specifically Kconfig and Makefiles, for references to both `bpf_tcp_ca` and `BPF_PROG_TYPE_STRUCT_OPS`. This will help me track down the dependencies. This should provide some immediate answers regarding the correct settings needed.



18/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "BPF_PROG_TYPE_STRUCT_OPS",
  "PathPrefix": "kernel/bpf"
}

Results:
{
  "Output": "kernel/bpf/bpf_struct_ops.c=726=static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,\n--\nkernel/bpf/bpf_struct_ops.c-845-\nkernel/bpf/bpf_struct_ops.c:846:\t\tif (prog-\u003etype != BPF_PROG_TYPE_STRUCT_OPS ||\nkernel/bpf/bpf_struct_ops.c-847-\t\t    prog-\u003eaux-\u003eattach_btf_id != st_ops_desc-\u003etype_id ||\n--\nkernel/bpf/bpf_struct_ops.c=1492=int bpf_prog_assoc_struct_ops(struct bpf_prog *prog, struct bpf_map *map)\n--\nkernel/bpf/bpf_struct_ops.c-1503-\tif (st_ops_assoc) {\nkernel/bpf/bpf_struct_ops.c:1504:\t\tif (prog-\u003etype != BPF_PROG_TYPE_STRUCT_OPS)\nkernel/bpf/bpf_struct_ops.c-1505-\t\t\treturn -EBUSY;\n--\nkernel/bpf/bpf_struct_ops.c-1512-\t\t */\nkernel/bpf/bpf_struct_ops.c:1513:\t\tif (prog-\u003etype != BPF_PROG_TYPE_STRUCT_OPS)\nkernel/bpf/bpf_struct_ops.c-1514-\t\t\tbpf_map_inc(map);\n--\nkernel/bpf/bpf_struct_ops.c=1522=void bpf_prog_disassoc_struct_ops(struct bpf_prog *prog)\n--\nkernel/bpf/bpf_struct_ops.c-1532-\nkernel/bpf/bpf_struct_ops.c:1533:\tif (prog-\u003etype != BPF_PROG_TYPE_STRUCT_OPS)\nkernel/bpf/bpf_struct_ops.c-1534-\t\tbpf_map_put(st_ops_assoc);\n--\nkernel/bpf/btf.c=6217=static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,\n--\nkernel/bpf/btf.c-6309-\tcase BPF_PROG_TYPE_LSM:\nkernel/bpf/btf.c:6310:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/btf.c-6311-\t\t/* allow u64* as ctx */\n--\nkernel/bpf/btf.c=6616=static bool prog_args_trusted(const struct bpf_prog *prog)\n--\nkernel/bpf/btf.c-6624-\t\treturn bpf_lsm_is_trusted(prog);\nkernel/bpf/btf.c:6625:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/btf.c-6626-\t\treturn true;\n--\nkernel/bpf/btf.c=9056=static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type)\n--\nkernel/bpf/btf.c-9064-\t\treturn BTF_KFUNC_HOOK_TC;\nkernel/bpf/btf.c:9065:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/btf.c-9066-\t\treturn BTF_KFUNC_HOOK_STRUCT_OPS;\n--\nkernel/bpf/core.c=2508=static bool __bpf_prog_map_compatible(struct bpf_map *map,\n--\nkernel/bpf/core.c-2560-\t\t\tcase BPF_PROG_TYPE_EXT:\nkernel/bpf/core.c:2561:\t\t\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/core.c-2562-\t\t\t\tret = false;\n--\nkernel/bpf/cpumask.c=515=static int __init cpumask_kfunc_init(void)\n--\nkernel/bpf/cpumask.c-526-\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, \u0026cpumask_kfunc_set);\nkernel/bpf/cpumask.c:527:\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, \u0026cpumask_kfunc_set);\nkernel/bpf/cpumask.c-528-\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, \u0026cpumask_kfunc_set);\n--\nkernel/bpf/helpers.c=4982=static int __init kfunc_init(void)\n--\nkernel/bpf/helpers.c-5000-\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, \u0026generic_kfunc_set);\nkernel/bpf/helpers.c:5001:\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, \u0026generic_kfunc_set);\nkernel/bpf/helpers.c-5002-\tret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, \u0026generic_kfunc_set);\n--\nkernel/bpf/syscall.c=2728=bpf_prog_load_check_attach(enum bpf_prog_type prog_type,\n--\nkernel/bpf/syscall.c-2743-\t\tcase BPF_PROG_TYPE_LSM:\nkernel/bpf/syscall.c:2744:\t\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/syscall.c-2745-\t\tcase BPF_PROG_TYPE_EXT:\n--\nkernel/bpf/syscall.c=2874=static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)\n--\nkernel/bpf/syscall.c-2883-\tcase BPF_PROG_TYPE_LSM:\nkernel/bpf/syscall.c:2884:\tcase BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */\nkernel/bpf/syscall.c-2885-\tcase BPF_PROG_TYPE_EXT: /* extends any prog */\n--\nkernel/bpf/syscall.c=6262=static int prog_assoc_struct_ops(union bpf_attr *attr)\n--\nkernel/bpf/syscall.c-6277-\nkernel/bpf/syscall.c:6278:\tif (prog-\u003etype == BPF_PROG_TYPE_STRUCT_OPS) {\nkernel/bpf/syscall.c-6279-\t\tret = -EINVAL;\n--\nkernel/bpf/verifier.c=5235=static enum priv_stack_mode bpf_enable_priv_stack(struct bpf_prog *prog)\n--\nkernel/bpf/verifier.c-5251-\tcase BPF_PROG_TYPE_LSM:\nkernel/bpf/verifier.c:5252:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/verifier.c-5253-\t\tif (prog-\u003eaux-\u003epriv_stack_requested || bpf_prog_check_recur(prog))\n--\nkernel/bpf/verifier.c=10499=static int check_reference_leak(struct bpf_verifier_env *env, bool exception_exit)\n--\nkernel/bpf/verifier.c-10515-\t\t */\nkernel/bpf/verifier.c:10516:\t\tif (type == BPF_PROG_TYPE_STRUCT_OPS \u0026\u0026 !exception_exit \u0026\u0026\nkernel/bpf/verifier.c-10517-\t\t    reg-\u003eid == state-\u003erefs[i].id)\n--\nkernel/bpf/verifier.c=17228=static bool return_retval_range(struct bpf_verifier_env *env, struct bpf_retval_range *range)\n--\nkernel/bpf/verifier.c-17322-\t\tbreak;\nkernel/bpf/verifier.c:17323:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/verifier.c-17324-\t\t*range = retval_range(0, 0);\n--\nkernel/bpf/verifier.c=17339=static bool program_returns_void(struct bpf_verifier_env *env)\n--\nkernel/bpf/verifier.c-17350-\t\tbreak;\nkernel/bpf/verifier.c:17351:\tcase BPF_PROG_TYPE_STRUCT_OPS:\nkernel/bpf/verifier.c-17352-\t\tif (!prog-\u003eaux-\u003eattach_func_proto-\u003etype)\n--\nkernel/bpf/verifier.c=17371=static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name)\n--\nkernel/bpf/verifier.c-17386-\nkernel/bpf/verifier.c:17387:\tif (prog_type == BPF_PROG_TYPE_STRUCT_OPS) {\nkernel/bpf/verifier.c-17388-\t\t/* Allow a struct_ops program to return a referenced kptr if it\n--\nkernel/bpf/verifier.c-17420-\nkernel/bpf/verifier.c:17421:\tif (prog_type == BPF_PROG_TYPE_STRUCT_OPS \u0026\u0026 !ret_type)\nkernel/bpf/verifier.c-17422-\t\treturn 0;\n--\nkernel/bpf/verifier.c=19267=static int do_check_common(struct bpf_verifier_env *env, int subprog)\n--\nkernel/bpf/verifier.c-19400-\t/* Acquire references for struct_ops program arguments tagged with \"__ref\" */\nkernel/bpf/verifier.c:19401:\tif (!subprog \u0026\u0026 env-\u003eprog-\u003etype == BPF_PROG_TYPE_STRUCT_OPS) {\nkernel/bpf/verifier.c-19402-\t\tfor (i = 0; i \u003c aux-\u003ectx_arg_info_size; i++) {\n--\nkernel/bpf/verifier.c=20276=static bool can_be_sleepable(struct bpf_prog *prog)\n--\nkernel/bpf/verifier.c-20297-\treturn prog-\u003etype == BPF_PROG_TYPE_KPROBE /* only for uprobes */ ||\nkernel/bpf/verifier.c:20298:\t       prog-\u003etype == BPF_PROG_TYPE_STRUCT_OPS ||\nkernel/bpf/verifier.c-20299-\t       prog-\u003etype == BPF_PROG_TYPE_RAW_TRACEPOINT ||\n--\nkernel/bpf/verifier.c=20303=static int check_attach_btf_id(struct bpf_verifier_env *env)\n--\nkernel/bpf/verifier.c-20325-\nkernel/bpf/verifier.c:20326:\tif (prog-\u003etype == BPF_PROG_TYPE_STRUCT_OPS)\nkernel/bpf/verifier.c-20327-\t\treturn check_struct_ops_btf_id(env);\n"
}

19/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 21443
							output: 30
							thoughts: 26
						

Thoughts:
Here's my thought process, as if I were considering this myself:

**Investigating the BPF Struct Ops Build Process**

Okay, so I need to figure out where `bpf_struct_ops.c` gets built. The most logical starting point, considering it's kernel-related and likely involves BPF, is the `kernel/bpf/Makefile`. That's where I'd expect to find the dependencies and build rules for anything BPF-specific within the kernel. Let's dive in and see what that Makefile has to say. Time to crack open that file and get to the bottom of the build process for `bpf_struct_ops.c`. Hopefully, it's straightforward, and I can quickly trace the relevant targets and sources.



20/2 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "bpf_struct_ops",
  "PathPrefix": "kernel/bpf"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 586 lines.\nUse more precise expression if possible.\n\nkernel/bpf/Makefile=43=ifeq ($(CONFIG_BPF_JIT),y)\nkernel/bpf/Makefile:44:obj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o\nkernel/bpf/Makefile-45-obj-$(CONFIG_BPF_SYSCALL) += cpumask.o\n--\nkernel/bpf/bpf_struct_ops.c-16-\nkernel/bpf/bpf_struct_ops.c:17:struct bpf_struct_ops_value {\nkernel/bpf/bpf_struct_ops.c:18:\tstruct bpf_struct_ops_common_value common;\nkernel/bpf/bpf_struct_ops.c-19-\tchar data[] ____cacheline_aligned_in_smp;\n--\nkernel/bpf/bpf_struct_ops.c-23-\nkernel/bpf/bpf_struct_ops.c:24:struct bpf_struct_ops_map {\nkernel/bpf/bpf_struct_ops.c-25-\tstruct bpf_map map;\nkernel/bpf/bpf_struct_ops.c:26:\tconst struct bpf_struct_ops_desc *st_ops_desc;\nkernel/bpf/bpf_struct_ops.c-27-\t/* protect map_update */\n--\nkernel/bpf/bpf_struct_ops.c-49-\t */\nkernel/bpf/bpf_struct_ops.c:50:\tstruct bpf_struct_ops_value *uvalue;\nkernel/bpf/bpf_struct_ops.c-51-\t/* kvalue.data stores the actual kernel's struct\n--\nkernel/bpf/bpf_struct_ops.c-54-\t */\nkernel/bpf/bpf_struct_ops.c:55:\tstruct bpf_struct_ops_value kvalue;\nkernel/bpf/bpf_struct_ops.c-56-};\nkernel/bpf/bpf_struct_ops.c-57-\nkernel/bpf/bpf_struct_ops.c:58:struct bpf_struct_ops_link {\nkernel/bpf/bpf_struct_ops.c-59-\tstruct bpf_link link;\n--\nkernel/bpf/bpf_struct_ops.c=64=static DEFINE_MUTEX(update_mutex);\nkernel/bpf/bpf_struct_ops.c-65-\nkernel/bpf/bpf_struct_ops.c:66:#define VALUE_PREFIX \"bpf_struct_ops_\"\nkernel/bpf/bpf_struct_ops.c-67-#define VALUE_PREFIX_LEN (sizeof(VALUE_PREFIX) - 1)\nkernel/bpf/bpf_struct_ops.c-68-\nkernel/bpf/bpf_struct_ops.c:69:const struct bpf_verifier_ops bpf_struct_ops_verifier_ops = {\nkernel/bpf/bpf_struct_ops.c-70-};\nkernel/bpf/bpf_struct_ops.c-71-\nkernel/bpf/bpf_struct_ops.c:72:const struct bpf_prog_ops bpf_struct_ops_prog_ops = {\nkernel/bpf/bpf_struct_ops.c-73-#ifdef CONFIG_NET\nkernel/bpf/bpf_struct_ops.c:74:\t.test_run = bpf_struct_ops_test_run,\nkernel/bpf/bpf_struct_ops.c-75-#endif\n--\nkernel/bpf/bpf_struct_ops.c=79=BTF_ID(struct, module)\nkernel/bpf/bpf_struct_ops.c:80:BTF_ID(struct, bpf_struct_ops_common_value)\nkernel/bpf/bpf_struct_ops.c-81-\n--\nkernel/bpf/bpf_struct_ops.c=89=static bool is_valid_value_type(struct btf *btf, s32 value_id,\n--\nkernel/bpf/bpf_struct_ops.c-107-\tif (mt != common_value_type) {\nkernel/bpf/bpf_struct_ops.c:108:\t\tpr_warn(\"The first member of %s should be bpf_struct_ops_common_value\\n\",\nkernel/bpf/bpf_struct_ops.c-109-\t\t\tvalue_name);\n--\nkernel/bpf/bpf_struct_ops.c-122-\nkernel/bpf/bpf_struct_ops.c:123:static void *bpf_struct_ops_image_alloc(void)\nkernel/bpf/bpf_struct_ops.c-124-{\n--\nkernel/bpf/bpf_struct_ops.c-139-\nkernel/bpf/bpf_struct_ops.c:140:void bpf_struct_ops_image_free(void *image)\nkernel/bpf/bpf_struct_ops.c-141-{\n--\nkernel/bpf/bpf_struct_ops.c-155- *\nkernel/bpf/bpf_struct_ops.c:156: * Initialize a struct bpf_struct_ops_arg_info according to type info of\nkernel/bpf/bpf_struct_ops.c-157- * the arguments of a stub function. (Check kCFI for more information about\n--\nkernel/bpf/bpf_struct_ops.c-159- *\nkernel/bpf/bpf_struct_ops.c:160: * Each member in the struct_ops type has a struct bpf_struct_ops_arg_info\nkernel/bpf/bpf_struct_ops.c-161- * to provide an array of struct bpf_ctx_arg_aux, which in turn provides\n--\nkernel/bpf/bpf_struct_ops.c=173=static int prepare_arg_info(struct btf *btf,\n--\nkernel/bpf/bpf_struct_ops.c-177-\t\t\t    struct btf_func_model *model,\nkernel/bpf/bpf_struct_ops.c:178:\t\t\t    struct bpf_struct_ops_arg_info *arg_info)\nkernel/bpf/bpf_struct_ops.c-179-{\n--\nkernel/bpf/bpf_struct_ops.c-323-\nkernel/bpf/bpf_struct_ops.c:324:/* Clean up the arg_info in a struct bpf_struct_ops_desc. */\nkernel/bpf/bpf_struct_ops.c:325:void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_ops_desc)\nkernel/bpf/bpf_struct_ops.c-326-{\nkernel/bpf/bpf_struct_ops.c:327:\tstruct bpf_struct_ops_arg_info *arg_info;\nkernel/bpf/bpf_struct_ops.c-328-\tint i;\n--\nkernel/bpf/bpf_struct_ops.c=337=static bool is_module_member(const struct btf *btf, u32 id)\n--\nkernel/bpf/bpf_struct_ops.c-350-\nkernel/bpf/bpf_struct_ops.c:351:int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff)\nkernel/bpf/bpf_struct_ops.c-352-{\n--\nkernel/bpf/bpf_struct_ops.c-357-\nkernel/bpf/bpf_struct_ops.c:358:int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,\nkernel/bpf/bpf_struct_ops.c-359-\t\t\t     struct btf *btf,\n--\nkernel/bpf/bpf_struct_ops.c-361-{\nkernel/bpf/bpf_struct_ops.c:362:\tstruct bpf_struct_ops *st_ops = st_ops_desc-\u003est_ops;\nkernel/bpf/bpf_struct_ops.c:363:\tstruct bpf_struct_ops_arg_info *arg_info;\nkernel/bpf/bpf_struct_ops.c-364-\tconst struct btf_member *member;\n--\nkernel/bpf/bpf_struct_ops.c-439-\t\tif (!st_ops_ids[IDX_MODULE_ID] \u0026\u0026 is_module_member(btf, member-\u003etype)) {\nkernel/bpf/bpf_struct_ops.c:440:\t\t\tpr_warn(\"'struct module' btf id not found. Is CONFIG_MODULES enabled? bpf_struct_ops '%s' needs module support.\\n\",\nkernel/bpf/bpf_struct_ops.c-441-\t\t\t\tst_ops-\u003ename);\n--\nkernel/bpf/bpf_struct_ops.c-452-\t\t */\nkernel/bpf/bpf_struct_ops.c:453:\t\tif (!func_proto || bpf_struct_ops_supported(st_ops, moff))\nkernel/bpf/bpf_struct_ops.c-454-\t\t\tcontinue;\n--\nkernel/bpf/bpf_struct_ops.c-496-\tif (st_ops-\u003einit(btf)) {\nkernel/bpf/bpf_struct_ops.c:497:\t\tpr_warn(\"Error in init bpf_struct_ops %s\\n\",\nkernel/bpf/bpf_struct_ops.c-498-\t\t\tst_ops-\u003ename);\n--\nkernel/bpf/bpf_struct_ops.c-505-errout:\nkernel/bpf/bpf_struct_ops.c:506:\tbpf_struct_ops_desc_release(st_ops_desc);\nkernel/bpf/bpf_struct_ops.c-507-\n--\nkernel/bpf/bpf_struct_ops.c-510-\nkernel/bpf/bpf_struct_ops.c:511:static int bpf_struct_ops_map_get_next_key(struct bpf_map *map, void *key,\nkernel/bpf/bpf_struct_ops.c-512-\t\t\t\t\t   void *next_key)\n--\nkernel/bpf/bpf_struct_ops.c-520-\nkernel/bpf/bpf_struct_ops.c:521:int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key,\nkernel/bpf/bpf_struct_ops.c-522-\t\t\t\t       void *value)\nkernel/bpf/bpf_struct_ops.c-523-{\nkernel/bpf/bpf_struct_ops.c:524:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c:525:\tstruct bpf_struct_ops_value *uvalue, *kvalue;\nkernel/bpf/bpf_struct_ops.c:526:\tenum bpf_struct_ops_state state;\nkernel/bpf/bpf_struct_ops.c-527-\ts64 refcnt;\n--\nkernel/bpf/bpf_struct_ops.c-557-\nkernel/bpf/bpf_struct_ops.c:558:static void *bpf_struct_ops_map_lookup_elem(struct bpf_map *map, void *key)\nkernel/bpf/bpf_struct_ops.c-559-{\n--\nkernel/bpf/bpf_struct_ops.c-562-\nkernel/bpf/bpf_struct_ops.c:563:static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-564-{\n--\nkernel/bpf/bpf_struct_ops.c-574-\nkernel/bpf/bpf_struct_ops.c:575:static void bpf_struct_ops_map_dissoc_progs(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-576-{\n--\nkernel/bpf/bpf_struct_ops.c-585-\nkernel/bpf/bpf_struct_ops.c:586:static void bpf_struct_ops_map_free_image(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-587-{\n--\nkernel/bpf/bpf_struct_ops.c-590-\tfor (i = 0; i \u003c st_map-\u003eimage_pages_cnt; i++)\nkernel/bpf/bpf_struct_ops.c:591:\t\tbpf_struct_ops_image_free(st_map-\u003eimage_pages[i]);\nkernel/bpf/bpf_struct_ops.c-592-\tst_map-\u003eimage_pages_cnt = 0;\n--\nkernel/bpf/bpf_struct_ops.c=595=static int check_zero_holes(const struct btf *btf, const struct btf_type *t, void *data)\n--\nkernel/bpf/bpf_struct_ops.c-620-\nkernel/bpf/bpf_struct_ops.c:621:static void bpf_struct_ops_link_release(struct bpf_link *link)\nkernel/bpf/bpf_struct_ops.c-622-{\n--\nkernel/bpf/bpf_struct_ops.c-624-\nkernel/bpf/bpf_struct_ops.c:625:static void bpf_struct_ops_link_dealloc(struct bpf_link *link)\nkernel/bpf/bpf_struct_ops.c-626-{\n--\nkernel/bpf/bpf_struct_ops.c-631-\nkernel/bpf/bpf_struct_ops.c:632:const struct bpf_link_ops bpf_struct_ops_link_lops = {\nkernel/bpf/bpf_struct_ops.c:633:\t.release = bpf_struct_ops_link_release,\nkernel/bpf/bpf_struct_ops.c:634:\t.dealloc = bpf_struct_ops_link_dealloc,\nkernel/bpf/bpf_struct_ops.c-635-};\nkernel/bpf/bpf_struct_ops.c-636-\nkernel/bpf/bpf_struct_ops.c:637:int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_nodes *tnodes,\nkernel/bpf/bpf_struct_ops.c-638-\t\t\t\t      struct bpf_tramp_node *node,\n--\nkernel/bpf/bpf_struct_ops.c-662-\nkernel/bpf/bpf_struct_ops.c:663:\t\timage = bpf_struct_ops_image_alloc();\nkernel/bpf/bpf_struct_ops.c-664-\t\tif (IS_ERR(image))\n--\nkernel/bpf/bpf_struct_ops.c-673-\t\tif (image != *_image)\nkernel/bpf/bpf_struct_ops.c:674:\t\t\tbpf_struct_ops_image_free(image);\nkernel/bpf/bpf_struct_ops.c-675-\t\treturn size ? : -EFAULT;\n--\nkernel/bpf/bpf_struct_ops.c-682-\nkernel/bpf/bpf_struct_ops.c:683:static void bpf_struct_ops_ksym_init(const char *tname, const char *mname,\nkernel/bpf/bpf_struct_ops.c-684-\t\t\t\t     void *image, unsigned int size,\n--\nkernel/bpf/bpf_struct_ops.c-691-\nkernel/bpf/bpf_struct_ops.c:692:static void bpf_struct_ops_map_add_ksyms(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-693-{\n--\nkernel/bpf/bpf_struct_ops.c-702-\nkernel/bpf/bpf_struct_ops.c:703:static void bpf_struct_ops_map_del_ksyms(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-704-{\n--\nkernel/bpf/bpf_struct_ops.c-713-\nkernel/bpf/bpf_struct_ops.c:714:static void bpf_struct_ops_map_free_ksyms(struct bpf_struct_ops_map *st_map)\nkernel/bpf/bpf_struct_ops.c-715-{\n--\nkernel/bpf/bpf_struct_ops.c-725-\nkernel/bpf/bpf_struct_ops.c:726:static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,\nkernel/bpf/bpf_struct_ops.c-727-\t\t\t\t\t   void *value, u64 flags)\nkernel/bpf/bpf_struct_ops.c-728-{\nkernel/bpf/bpf_struct_ops.c:729:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c:730:\tconst struct bpf_struct_ops_desc *st_ops_desc = st_map-\u003est_ops_desc;\nkernel/bpf/bpf_struct_ops.c:731:\tconst struct bpf_struct_ops *st_ops = st_ops_desc-\u003est_ops;\nkernel/bpf/bpf_struct_ops.c:732:\tstruct bpf_struct_ops_value *uvalue, *kvalue;\nkernel/bpf/bpf_struct_ops.c-733-\tconst struct btf_type *module_type;\n--\nkernel/bpf/bpf_struct_ops.c-766-\nkernel/bpf/bpf_struct_ops.c:767:\tuvalue = (struct bpf_struct_ops_value *)st_map-\u003euvalue;\nkernel/bpf/bpf_struct_ops.c:768:\tkvalue = (struct bpf_struct_ops_value *)\u0026st_map-\u003ekvalue;\nkernel/bpf/bpf_struct_ops.c-769-\n--\nkernel/bpf/bpf_struct_ops.c-860-\t\tbpf_tramp_link_init(link, BPF_LINK_TYPE_STRUCT_OPS,\nkernel/bpf/bpf_struct_ops.c:861:\t\t\t      \u0026bpf_struct_ops_link_lops, prog, prog-\u003eexpected_attach_type, 0);\nkernel/bpf/bpf_struct_ops.c-862-\n--\nkernel/bpf/bpf_struct_ops.c-875-\t\ttrampoline_start = image_off;\nkernel/bpf/bpf_struct_ops.c:876:\t\terr = bpf_struct_ops_prepare_trampoline(tnodes, \u0026link-\u003enode,\nkernel/bpf/bpf_struct_ops.c-877-\t\t\t\t\t\t\u0026st_ops-\u003efunc_models[i],\n--\nkernel/bpf/bpf_struct_ops.c-895-\t\t/* init ksym for this trampoline */\nkernel/bpf/bpf_struct_ops.c:896:\t\tbpf_struct_ops_ksym_init(tname, mname,\nkernel/bpf/bpf_struct_ops.c-897-\t\t\t\t\t image + trampoline_start,\n--\nkernel/bpf/bpf_struct_ops.c-928-\t\t * map must be set to INIT at this moment, and thus\nkernel/bpf/bpf_struct_ops.c:929:\t\t * bpf_struct_ops_map_delete_elem() can't unregister\nkernel/bpf/bpf_struct_ops.c-930-\t\t * or transition it to TOBEFREE concurrently.\n--\nkernel/bpf/bpf_struct_ops.c-947-reset_unlock:\nkernel/bpf/bpf_struct_ops.c:948:\tbpf_struct_ops_map_free_ksyms(st_map);\nkernel/bpf/bpf_struct_ops.c:949:\tbpf_struct_ops_map_free_image(st_map);\nkernel/bpf/bpf_struct_ops.c:950:\tbpf_struct_ops_map_dissoc_progs(st_map);\nkernel/bpf/bpf_struct_ops.c:951:\tbpf_struct_ops_map_put_progs(st_map);\nkernel/bpf/bpf_struct_ops.c-952-\tmemset(uvalue, 0, map-\u003evalue_size);\n--\nkernel/bpf/bpf_struct_ops.c-957-\tif (!err)\nkernel/bpf/bpf_struct_ops.c:958:\t\tbpf_struct_ops_map_add_ksyms(st_map);\nkernel/bpf/bpf_struct_ops.c-959-\treturn err;\n--\nkernel/bpf/bpf_struct_ops.c-961-\nkernel/bpf/bpf_struct_ops.c:962:static long bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key)\nkernel/bpf/bpf_struct_ops.c-963-{\nkernel/bpf/bpf_struct_ops.c:964:\tenum bpf_struct_ops_state prev_state;\nkernel/bpf/bpf_struct_ops.c:965:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-966-\nkernel/bpf/bpf_struct_ops.c:967:\tst_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-968-\tif (st_map-\u003emap.map_flags \u0026 BPF_F_LINK)\n--\nkernel/bpf/bpf_struct_ops.c-989-\nkernel/bpf/bpf_struct_ops.c:990:static void bpf_struct_ops_map_seq_show_elem(struct bpf_map *map, void *key,\nkernel/bpf/bpf_struct_ops.c-991-\t\t\t\t\t     struct seq_file *m)\nkernel/bpf/bpf_struct_ops.c-992-{\nkernel/bpf/bpf_struct_ops.c:993:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-994-\tvoid *value;\n--\nkernel/bpf/bpf_struct_ops.c-1000-\nkernel/bpf/bpf_struct_ops.c:1001:\terr = bpf_struct_ops_map_sys_lookup_elem(map, key, value);\nkernel/bpf/bpf_struct_ops.c-1002-\tif (!err) {\n--\nkernel/bpf/bpf_struct_ops.c-1011-\nkernel/bpf/bpf_struct_ops.c:1012:static void __bpf_struct_ops_map_free(struct bpf_map *map)\nkernel/bpf/bpf_struct_ops.c-1013-{\nkernel/bpf/bpf_struct_ops.c:1014:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-1015-\nkernel/bpf/bpf_struct_ops.c-1016-\tif (st_map-\u003elinks)\nkernel/bpf/bpf_struct_ops.c:1017:\t\tbpf_struct_ops_map_put_progs(st_map);\nkernel/bpf/bpf_struct_ops.c-1018-\tif (st_map-\u003eksyms)\nkernel/bpf/bpf_struct_ops.c:1019:\t\tbpf_struct_ops_map_free_ksyms(st_map);\nkernel/bpf/bpf_struct_ops.c-1020-\tbpf_map_area_free(st_map-\u003elinks);\nkernel/bpf/bpf_struct_ops.c-1021-\tbpf_map_area_free(st_map-\u003eksyms);\nkernel/bpf/bpf_struct_ops.c:1022:\tbpf_struct_ops_map_free_image(st_map);\nkernel/bpf/bpf_struct_ops.c-1023-\tbpf_map_area_free(st_map-\u003euvalue);\n--\nkernel/bpf/bpf_struct_ops.c-1026-\nkernel/bpf/bpf_struct_ops.c:1027:static void bpf_struct_ops_map_free(struct bpf_map *map)\nkernel/bpf/bpf_struct_ops.c-1028-{\nkernel/bpf/bpf_struct_ops.c:1029:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-1030-\n--\nkernel/bpf/bpf_struct_ops.c-1037-\nkernel/bpf/bpf_struct_ops.c:1038:\tbpf_struct_ops_map_dissoc_progs(st_map);\nkernel/bpf/bpf_struct_ops.c-1039-\nkernel/bpf/bpf_struct_ops.c:1040:\tbpf_struct_ops_map_del_ksyms(st_map);\nkernel/bpf/bpf_struct_ops.c-1041-\n--\nkernel/bpf/bpf_struct_ops.c-1046-\t * setsockopt(TCP_CONGESTION, \"tcp_cc_y\").\nkernel/bpf/bpf_struct_ops.c:1047:\t * During the switch,  bpf_struct_ops_put(tcp_cc_x) is called\nkernel/bpf/bpf_struct_ops.c-1048-\t * and its refcount may reach 0 which then free its\n--\nkernel/bpf/bpf_struct_ops.c-1058-\nkernel/bpf/bpf_struct_ops.c:1059:\t__bpf_struct_ops_map_free(map);\nkernel/bpf/bpf_struct_ops.c-1060-}\nkernel/bpf/bpf_struct_ops.c-1061-\nkernel/bpf/bpf_struct_ops.c:1062:static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr)\nkernel/bpf/bpf_struct_ops.c-1063-{\n--\nkernel/bpf/bpf_struct_ops.c=1071=static u32 count_func_ptrs(const struct btf *btf, const struct btf_type *t)\n--\nkernel/bpf/bpf_struct_ops.c-1083-\nkernel/bpf/bpf_struct_ops.c:1084:static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)\nkernel/bpf/bpf_struct_ops.c-1085-{\nkernel/bpf/bpf_struct_ops.c:1086:\tconst struct bpf_struct_ops_desc *st_ops_desc;\nkernel/bpf/bpf_struct_ops.c-1087-\tsize_t st_map_size;\nkernel/bpf/bpf_struct_ops.c:1088:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1089-\tconst struct btf_type *t, *vt;\n--\nkernel/bpf/bpf_struct_ops.c-1119-\nkernel/bpf/bpf_struct_ops.c:1120:\tst_ops_desc = bpf_struct_ops_find_value(btf, attr-\u003ebtf_vmlinux_value_type_id);\nkernel/bpf/bpf_struct_ops.c-1121-\tif (!st_ops_desc) {\n--\nkernel/bpf/bpf_struct_ops.c-1135-\t\t/* kvalue stores the\nkernel/bpf/bpf_struct_ops.c:1136:\t\t * struct bpf_struct_ops_tcp_congestions_ops\nkernel/bpf/bpf_struct_ops.c-1137-\t\t */\nkernel/bpf/bpf_struct_ops.c:1138:\t\t(vt-\u003esize - sizeof(struct bpf_struct_ops_value));\nkernel/bpf/bpf_struct_ops.c-1139-\n--\nkernel/bpf/bpf_struct_ops.c-1169-errout_free:\nkernel/bpf/bpf_struct_ops.c:1170:\t__bpf_struct_ops_map_free(map);\nkernel/bpf/bpf_struct_ops.c-1171-errout:\n--\nkernel/bpf/bpf_struct_ops.c-1176-\nkernel/bpf/bpf_struct_ops.c:1177:static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map)\nkernel/bpf/bpf_struct_ops.c-1178-{\nkernel/bpf/bpf_struct_ops.c:1179:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c:1180:\tconst struct bpf_struct_ops_desc *st_ops_desc = st_map-\u003est_ops_desc;\nkernel/bpf/bpf_struct_ops.c-1181-\tconst struct btf_type *vt = st_ops_desc-\u003evalue_type;\n--\nkernel/bpf/bpf_struct_ops.c-1184-\tusage = sizeof(*st_map) +\nkernel/bpf/bpf_struct_ops.c:1185:\t\t\tvt-\u003esize - sizeof(struct bpf_struct_ops_value);\nkernel/bpf/bpf_struct_ops.c-1186-\tusage += vt-\u003esize;\n--\nkernel/bpf/bpf_struct_ops.c-1192-\nkernel/bpf/bpf_struct_ops.c:1193:BTF_ID_LIST_SINGLE(bpf_struct_ops_map_btf_ids, struct, bpf_struct_ops_map)\nkernel/bpf/bpf_struct_ops.c:1194:const struct bpf_map_ops bpf_struct_ops_map_ops = {\nkernel/bpf/bpf_struct_ops.c:1195:\t.map_alloc_check = bpf_struct_ops_map_alloc_check,\nkernel/bpf/bpf_struct_ops.c:1196:\t.map_alloc = bpf_struct_ops_map_alloc,\nkernel/bpf/bpf_struct_ops.c:1197:\t.map_free = bpf_struct_ops_map_free,\nkernel/bpf/bpf_struct_ops.c:1198:\t.map_get_next_key = bpf_struct_ops_map_get_next_key,\nkernel/bpf/bpf_struct_ops.c:1199:\t.map_lookup_elem = bpf_struct_ops_map_lookup_elem,\nkernel/bpf/bpf_struct_ops.c:1200:\t.map_delete_elem = bpf_struct_ops_map_delete_elem,\nkernel/bpf/bpf_struct_ops.c:1201:\t.map_update_elem = bpf_struct_ops_map_update_elem,\nkernel/bpf/bpf_struct_ops.c:1202:\t.map_seq_show_elem = bpf_struct_ops_map_seq_show_elem,\nkernel/bpf/bpf_struct_ops.c:1203:\t.map_mem_usage = bpf_struct_ops_map_mem_usage,\nkernel/bpf/bpf_struct_ops.c:1204:\t.map_btf_id = \u0026bpf_struct_ops_map_btf_ids[0],\nkernel/bpf/bpf_struct_ops.c-1205-};\n--\nkernel/bpf/bpf_struct_ops.c-1209- */\nkernel/bpf/bpf_struct_ops.c:1210:bool bpf_struct_ops_get(const void *kdata)\nkernel/bpf/bpf_struct_ops.c-1211-{\nkernel/bpf/bpf_struct_ops.c:1212:\tstruct bpf_struct_ops_value *kvalue;\nkernel/bpf/bpf_struct_ops.c:1213:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1214-\tstruct bpf_map *map;\nkernel/bpf/bpf_struct_ops.c-1215-\nkernel/bpf/bpf_struct_ops.c:1216:\tkvalue = container_of(kdata, struct bpf_struct_ops_value, data);\nkernel/bpf/bpf_struct_ops.c:1217:\tst_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue);\nkernel/bpf/bpf_struct_ops.c-1218-\n--\nkernel/bpf/bpf_struct_ops.c-1221-}\nkernel/bpf/bpf_struct_ops.c:1222:EXPORT_SYMBOL_GPL(bpf_struct_ops_get);\nkernel/bpf/bpf_struct_ops.c-1223-\nkernel/bpf/bpf_struct_ops.c:1224:void bpf_struct_ops_put(const void *kdata)\nkernel/bpf/bpf_struct_ops.c-1225-{\nkernel/bpf/bpf_struct_ops.c:1226:\tstruct bpf_struct_ops_value *kvalue;\nkernel/bpf/bpf_struct_ops.c:1227:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1228-\nkernel/bpf/bpf_struct_ops.c:1229:\tkvalue = container_of(kdata, struct bpf_struct_ops_value, data);\nkernel/bpf/bpf_struct_ops.c:1230:\tst_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue);\nkernel/bpf/bpf_struct_ops.c-1231-\n--\nkernel/bpf/bpf_struct_ops.c-1233-}\nkernel/bpf/bpf_struct_ops.c:1234:EXPORT_SYMBOL_GPL(bpf_struct_ops_put);\nkernel/bpf/bpf_struct_ops.c-1235-\nkernel/bpf/bpf_struct_ops.c:1236:u32 bpf_struct_ops_id(const void *kdata)\nkernel/bpf/bpf_struct_ops.c-1237-{\nkernel/bpf/bpf_struct_ops.c:1238:\tstruct bpf_struct_ops_value *kvalue;\nkernel/bpf/bpf_struct_ops.c:1239:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1240-\nkernel/bpf/bpf_struct_ops.c:1241:\tkvalue = container_of(kdata, struct bpf_struct_ops_value, data);\nkernel/bpf/bpf_struct_ops.c:1242:\tst_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue);\nkernel/bpf/bpf_struct_ops.c-1243-\n--\nkernel/bpf/bpf_struct_ops.c-1245-}\nkernel/bpf/bpf_struct_ops.c:1246:EXPORT_SYMBOL_GPL(bpf_struct_ops_id);\nkernel/bpf/bpf_struct_ops.c-1247-\nkernel/bpf/bpf_struct_ops.c-1248-/**\nkernel/bpf/bpf_struct_ops.c:1249: * bpf_struct_ops_for_each_prog - Invoke @cb for each member prog\nkernel/bpf/bpf_struct_ops.c-1250- * @kdata: kernel-side struct_ops vmtable (the @kdata arg to -\u003ereg/-\u003eupdate/-\u003eunreg)\n--\nkernel/bpf/bpf_struct_ops.c-1260- */\nkernel/bpf/bpf_struct_ops.c:1261:int bpf_struct_ops_for_each_prog(const void *kdata,\nkernel/bpf/bpf_struct_ops.c-1262-\t\t\t\t int (*cb)(struct bpf_prog *prog, void *data),\n--\nkernel/bpf/bpf_struct_ops.c-1264-{\nkernel/bpf/bpf_struct_ops.c:1265:\tstruct bpf_struct_ops_value *kvalue;\nkernel/bpf/bpf_struct_ops.c:1266:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1267-\tu32 i;\n--\nkernel/bpf/bpf_struct_ops.c-1269-\nkernel/bpf/bpf_struct_ops.c:1270:\tkvalue = container_of(kdata, struct bpf_struct_ops_value, data);\nkernel/bpf/bpf_struct_ops.c:1271:\tst_map = container_of(kvalue, struct bpf_struct_ops_map, kvalue);\nkernel/bpf/bpf_struct_ops.c-1272-\n--\nkernel/bpf/bpf_struct_ops.c-1281-}\nkernel/bpf/bpf_struct_ops.c:1282:EXPORT_SYMBOL_GPL(bpf_struct_ops_for_each_prog);\nkernel/bpf/bpf_struct_ops.c-1283-\nkernel/bpf/bpf_struct_ops.c:1284:static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map)\nkernel/bpf/bpf_struct_ops.c-1285-{\nkernel/bpf/bpf_struct_ops.c:1286:\tstruct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-1287-\n--\nkernel/bpf/bpf_struct_ops.c-1293-\nkernel/bpf/bpf_struct_ops.c:1294:static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link)\nkernel/bpf/bpf_struct_ops.c-1295-{\nkernel/bpf/bpf_struct_ops.c:1296:\tstruct bpf_struct_ops_link *st_link;\nkernel/bpf/bpf_struct_ops.c:1297:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1298-\nkernel/bpf/bpf_struct_ops.c:1299:\tst_link = container_of(link, struct bpf_struct_ops_link, link);\nkernel/bpf/bpf_struct_ops.c:1300:\tst_map = (struct bpf_struct_ops_map *)\nkernel/bpf/bpf_struct_ops.c-1301-\t\trcu_dereference_protected(st_link-\u003emap, true);\n--\nkernel/bpf/bpf_struct_ops.c-1308-\nkernel/bpf/bpf_struct_ops.c:1309:static void bpf_struct_ops_map_link_show_fdinfo(const struct bpf_link *link,\nkernel/bpf/bpf_struct_ops.c-1310-\t\t\t\t\t    struct seq_file *seq)\nkernel/bpf/bpf_struct_ops.c-1311-{\nkernel/bpf/bpf_struct_ops.c:1312:\tstruct bpf_struct_ops_link *st_link;\nkernel/bpf/bpf_struct_ops.c-1313-\tstruct bpf_map *map;\nkernel/bpf/bpf_struct_ops.c-1314-\nkernel/bpf/bpf_struct_ops.c:1315:\tst_link = container_of(link, struct bpf_struct_ops_link, link);\nkernel/bpf/bpf_struct_ops.c-1316-\trcu_read_lock();\n--\nkernel/bpf/bpf_struct_ops.c-1322-\nkernel/bpf/bpf_struct_ops.c:1323:static int bpf_struct_ops_map_link_fill_link_info(const struct bpf_link *link,\nkernel/bpf/bpf_struct_ops.c-1324-\t\t\t\t\t       struct bpf_link_info *info)\nkernel/bpf/bpf_struct_ops.c-1325-{\nkernel/bpf/bpf_struct_ops.c:1326:\tstruct bpf_struct_ops_link *st_link;\nkernel/bpf/bpf_struct_ops.c-1327-\tstruct bpf_map *map;\nkernel/bpf/bpf_struct_ops.c-1328-\nkernel/bpf/bpf_struct_ops.c:1329:\tst_link = container_of(link, struct bpf_struct_ops_link, link);\nkernel/bpf/bpf_struct_ops.c-1330-\trcu_read_lock();\n--\nkernel/bpf/bpf_struct_ops.c-1337-\nkernel/bpf/bpf_struct_ops.c:1338:static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map *new_map,\nkernel/bpf/bpf_struct_ops.c-1339-\t\t\t\t\t  struct bpf_map *expected_old_map)\nkernel/bpf/bpf_struct_ops.c-1340-{\nkernel/bpf/bpf_struct_ops.c:1341:\tstruct bpf_struct_ops_map *st_map, *old_st_map;\nkernel/bpf/bpf_struct_ops.c-1342-\tstruct bpf_map *old_map;\nkernel/bpf/bpf_struct_ops.c:1343:\tstruct bpf_struct_ops_link *st_link;\nkernel/bpf/bpf_struct_ops.c-1344-\tint err;\nkernel/bpf/bpf_struct_ops.c-1345-\nkernel/bpf/bpf_struct_ops.c:1346:\tst_link = container_of(link, struct bpf_struct_ops_link, link);\nkernel/bpf/bpf_struct_ops.c:1347:\tst_map = container_of(new_map, struct bpf_struct_ops_map, map);\nkernel/bpf/bpf_struct_ops.c-1348-\nkernel/bpf/bpf_struct_ops.c:1349:\tif (!bpf_struct_ops_valid_to_reg(new_map))\nkernel/bpf/bpf_struct_ops.c-1350-\t\treturn -EINVAL;\n--\nkernel/bpf/bpf_struct_ops.c-1366-\nkernel/bpf/bpf_struct_ops.c:1367:\told_st_map = container_of(old_map, struct bpf_struct_ops_map, map);\nkernel/bpf/bpf_struct_ops.c-1368-\t/* The new and old struct_ops must be the same type. */\n--\nkernel/bpf/bpf_struct_ops.c-1387-\nkernel/bpf/bpf_struct_ops.c:1388:static int bpf_struct_ops_map_link_detach(struct bpf_link *link)\nkernel/bpf/bpf_struct_ops.c-1389-{\nkernel/bpf/bpf_struct_ops.c:1390:\tstruct bpf_struct_ops_link *st_link = container_of(link, struct bpf_struct_ops_link, link);\nkernel/bpf/bpf_struct_ops.c:1391:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1392-\tstruct bpf_map *map;\n--\nkernel/bpf/bpf_struct_ops.c-1400-\t}\nkernel/bpf/bpf_struct_ops.c:1401:\tst_map = container_of(map, struct bpf_struct_ops_map, map);\nkernel/bpf/bpf_struct_ops.c-1402-\n--\nkernel/bpf/bpf_struct_ops.c-1405-\tRCU_INIT_POINTER(st_link-\u003emap, NULL);\nkernel/bpf/bpf_struct_ops.c:1406:\t/* Pair with bpf_map_get() in bpf_struct_ops_link_create() or\nkernel/bpf/bpf_struct_ops.c:1407:\t * bpf_map_inc() in bpf_struct_ops_map_link_update().\nkernel/bpf/bpf_struct_ops.c-1408-\t */\n--\nkernel/bpf/bpf_struct_ops.c-1417-\nkernel/bpf/bpf_struct_ops.c:1418:static __poll_t bpf_struct_ops_map_link_poll(struct file *file,\nkernel/bpf/bpf_struct_ops.c-1419-\t\t\t\t\t     struct poll_table_struct *pts)\nkernel/bpf/bpf_struct_ops.c-1420-{\nkernel/bpf/bpf_struct_ops.c:1421:\tstruct bpf_struct_ops_link *st_link = file-\u003eprivate_data;\nkernel/bpf/bpf_struct_ops.c-1422-\n--\nkernel/bpf/bpf_struct_ops.c-1427-\nkernel/bpf/bpf_struct_ops.c:1428:static const struct bpf_link_ops bpf_struct_ops_map_lops = {\nkernel/bpf/bpf_struct_ops.c:1429:\t.dealloc = bpf_struct_ops_map_link_dealloc,\nkernel/bpf/bpf_struct_ops.c:1430:\t.detach = bpf_struct_ops_map_link_detach,\nkernel/bpf/bpf_struct_ops.c:1431:\t.show_fdinfo = bpf_struct_ops_map_link_show_fdinfo,\nkernel/bpf/bpf_struct_ops.c:1432:\t.fill_link_info = bpf_struct_ops_map_link_fill_link_info,\nkernel/bpf/bpf_struct_ops.c:1433:\t.update_map = bpf_struct_ops_map_link_update,\nkernel/bpf/bpf_struct_ops.c:1434:\t.poll = bpf_struct_ops_map_link_poll,\nkernel/bpf/bpf_struct_ops.c-1435-};\nkernel/bpf/bpf_struct_ops.c-1436-\nkernel/bpf/bpf_struct_ops.c:1437:int bpf_struct_ops_link_create(union bpf_attr *attr)\nkernel/bpf/bpf_struct_ops.c-1438-{\nkernel/bpf/bpf_struct_ops.c:1439:\tstruct bpf_struct_ops_link *link = NULL;\nkernel/bpf/bpf_struct_ops.c-1440-\tstruct bpf_link_primer link_primer;\nkernel/bpf/bpf_struct_ops.c:1441:\tstruct bpf_struct_ops_map *st_map;\nkernel/bpf/bpf_struct_ops.c-1442-\tstruct bpf_map *map;\n--\nkernel/bpf/bpf_struct_ops.c-1448-\nkernel/bpf/bpf_struct_ops.c:1449:\tst_map = (struct bpf_struct_ops_map *)map;\nkernel/bpf/bpf_struct_ops.c-1450-\nkernel/bpf/bpf_struct_ops.c:1451:\tif (!bpf_struct_ops_valid_to_reg(map)) {\nkernel/bpf/bpf_struct_ops.c-1452-\t\terr = -EINVAL;\n--\nkernel/bpf/bpf_struct_ops.c-1460-\t}\nkernel/bpf/bpf_struct_ops.c:1461:\tbpf_link_init(\u0026link-\u003elink, BPF_LINK_TYPE_STRUCT_OPS, \u0026bpf_struct_ops_map_lops, NULL,\nkernel/bpf/bpf_struct_ops.c-1462-\t\t      attr-\u003elink_create.attach_type);\n--\nkernel/bpf/bpf_struct_ops.c=1549=void *bpf_prog_get_assoc_struct_ops(const struct bpf_prog_aux *aux)\nkernel/bpf/bpf_struct_ops.c-1550-{\nkernel/bpf/bpf_struct_ops.c:1551:\tstruct bpf_struct_ops_map *st_map;\n\n"
}

21/2 2026/09/01 01:32 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 34851
							output: 179
							thoughts: 289
						

Thoughts:
**My Assessment of the Configuration Changes**

Okay, let's take a look at these configurations. First, I need to verify that we have the necessary kernel modules enabled. I want to confirm that `TCP_CONG_BBR` is enabled, as it provides the BBR TCP congestion control module, which is crucial because it implements `tso_segs`. Then, I'll double-check that `BPF_SYSCALL` and `BPF_JIT` are also enabled; these are essential because they're directly related to `bpf_tcp_ca.c` and BPF TCP congestion operations. Of course, `NET` and `INET` are our base networking prerequisites, so I assume those are already in place, but I will check to be certain.

Now, let's see if there are any other related symbols or configurations I should be aware of. The key symbol I'm focusing on right now is `tcp_tso_autosize`.

Next, I need to thoroughly review the parameters for the `set-results` tool call. We need to be absolutely precise here. `WorthFuzzing` must be set to `true`, as the patch is going to modify TCP TSO autosizing logic and congestion control operations, notably replacing `min_tso_segs` with `tso_segs`. It also updates the BBR and BPF TCP CA callbacks, which is significant. Furthermore, the patch exports `tcp_tso_autosize` as a BPF kfunc. All of this directly impacts TCP packet segmentation and how these packets are transmitted within core networking. The `Reasoning` should make this very clear, so I'll write a detailed explanation.

For `FocusSymbols`, I will use `["tcp_tso_autosize"]`. And for `EnableConfigs`, I'll include the following: `["TCP_CONG_BBR", "BPF_SYSCALL", "BPF_JIT", "INET"]`.

Finally, I'll do a quick double-check of everything related to the `set-results` tool call. Precision is paramount here.



22/2 2026/09/01 01:32 tool set-results
0m Args:
{
  "EnableConfigs": [
    "TCP_CONG_BBR",
    "BPF_SYSCALL",
    "BPF_JIT",
    "INET"
  ],
  "FocusSymbols": [
    "tcp_tso_autosize"
  ],
  "Reasoning": "The patch refactors the TCP congestion control ops interface by replacing the min_tso_segs callback with a tso_segs callback, updating TCP output logic (tcp_tso_autosize, tcp_tso_segs), BBR congestion control, and BPF TCP CA struct_ops. tcp_tso_autosize is also exposed as a BPF kfunc. These functional changes alter the TCP segmentation and packet scheduling path in the core networking stack and are reachable and testable in virtualized environments.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "TCP_CONG_BBR",
    "BPF_SYSCALL",
    "BPF_JIT",
    "INET"
  ],
  "FocusSymbols": [
    "tcp_tso_autosize"
  ],
  "Reasoning": "The patch refactors the TCP congestion control ops interface by replacing the min_tso_segs callback with a tso_segs callback, updating TCP output logic (tcp_tso_autosize, tcp_tso_segs), BBR congestion control, and BPF TCP CA struct_ops. tcp_tso_autosize is also exposed as a BPF kfunc. These functional changes alter the TCP segmentation and packet scheduling path in the core networking stack and are reachable and testable in virtualized environments.",
  "WorthFuzzing": true
}

23/1 2026/09/01 01:32 action If
0m Args:
{
  "WorthFuzzing": true
}

Results:
null

24/2 2026/09/01 01:32 agent kmsan-evaluator
0m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch refactors the TCP congestion control ops interface by replacing the `min_tso_segs` callback with `tso_segs(struct sock *sk, u32 mss_now)`, updates BBR and BPF congestion control hooks, and exports `tcp_tso_autosize` as a BPF kfunc.\n\nAll modified and added functions operate on scalar integer values passed by value (`u32`, `unsigned int`, pointers to fully initialized struct `sock`). No new memory allocations, stack/heap structures, or data copies to user-space (such as `copy_to_user`, netlink attributes, or ioctl returns) are introduced or modified. There is no risk of uninitialized memory reads or information leaks to user space. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 47feec24ae21044cf7cda2f66f6fb37454b5537b
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Sep 1 01:31:44 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 670c20876f265..79f27ac9e963a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -824,6 +824,9 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);
 unsigned int tcp_current_mss(struct sock *sk);
 u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when);
 
+u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
+		     int min_tso_segs);
+
 /* Bound MSS / TSO packet size with the half of the window */
 static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
 {
@@ -1361,8 +1364,16 @@ struct tcp_congestion_ops {
 	/* hook for packet ack accounting (optional) */
 	void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample);
 
-	/* override sysctl_tcp_min_tso_segs (optional) */
-	u32 (*min_tso_segs)(struct sock *sk);
+	/* Override tcp_tso_autosize() (optional)
+	 *
+	 * If provided, this callback supplies the TSO segment target count
+	 * instead of using tcp_tso_autosize(). The returned value is
+	 * subsequently clamped to [1, sk->sk_gso_max_segs] by the caller.
+	 *
+	 * For the kernel callback path, mss_now originates from
+	 * tcp_current_mss() and should never be zero.
+	 */
+	u32 (*tso_segs)(struct sock *sk, u32 mss_now);
 
 	/* new value of cwnd after loss (required) */
 	u32  (*undo_cwnd)(struct sock *sk);
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index 791e15063237c..9deed2244c2de 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -194,6 +194,7 @@ BTF_ID_FLAGS(func, tcp_reno_cong_avoid)
 BTF_ID_FLAGS(func, tcp_reno_undo_cwnd)
 BTF_ID_FLAGS(func, tcp_slow_start)
 BTF_ID_FLAGS(func, tcp_cong_avoid_ai)
+BTF_ID_FLAGS(func, tcp_tso_autosize)
 BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids)
 
 static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = {
@@ -284,7 +285,7 @@ static void bpf_tcp_ca_pkts_acked(struct sock *sk, const struct ack_sample *samp
 {
 }
 
-static u32 bpf_tcp_ca_min_tso_segs(struct sock *sk)
+static u32 bpf_tcp_ca_tso_segs(struct sock *sk, u32 mss_now)
 {
 	return 0;
 }
@@ -320,7 +321,7 @@ static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = {
 	.cwnd_event_tx_start = bpf_tcp_ca_cwnd_event_tx_start,
 	.in_ack_event = bpf_tcp_ca_in_ack_event,
 	.pkts_acked = bpf_tcp_ca_pkts_acked,
-	.min_tso_segs = bpf_tcp_ca_min_tso_segs,
+	.tso_segs = bpf_tcp_ca_tso_segs,
 	.cong_control = bpf_tcp_ca_cong_control,
 	.undo_cwnd = bpf_tcp_ca_undo_cwnd,
 	.sndbuf_expand = bpf_tcp_ca_sndbuf_expand,
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 82378a2bfd1e1..ecf11be46f382 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -297,11 +297,18 @@ static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)
 }
 
 /* override sysctl_tcp_min_tso_segs */
-__bpf_kfunc static u32 bbr_min_tso_segs(struct sock *sk)
+static u32 bbr_min_tso_segs(struct sock *sk)
 {
 	return READ_ONCE(sk->sk_pacing_rate) < (bbr_min_tso_rate >> 3) ? 1 : 2;
 }
 
+__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)
+{
+	if (unlikely(!mss_now))
+		return bbr_min_tso_segs(sk);
+	return tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));
+}
+
 static u32 bbr_tso_segs_goal(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -1151,7 +1158,7 @@ static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = {
 	.undo_cwnd	= bbr_undo_cwnd,
 	.cwnd_event_tx_start	= bbr_cwnd_event_tx_start,
 	.ssthresh	= bbr_ssthresh,
-	.min_tso_segs	= bbr_min_tso_segs,
+	.tso_segs	= bbr_tso_segs,
 	.get_info	= bbr_get_info,
 	.set_state	= bbr_set_state,
 };
@@ -1163,7 +1170,7 @@ BTF_ID_FLAGS(func, bbr_sndbuf_expand)
 BTF_ID_FLAGS(func, bbr_undo_cwnd)
 BTF_ID_FLAGS(func, bbr_cwnd_event_tx_start)
 BTF_ID_FLAGS(func, bbr_ssthresh)
-BTF_ID_FLAGS(func, bbr_min_tso_segs)
+BTF_ID_FLAGS(func, bbr_tso_segs)
 BTF_ID_FLAGS(func, bbr_set_state)
 BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids)
 
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 6f4dca4a4de98..b7f2ee5e7a6b1 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2252,13 +2252,21 @@ static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,
  * in bigger TSO bursts. We we cut the RTT-based allowance in half
  * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance
  * is below 1500 bytes after 6 * ~500 usec = 3ms.
+ *
+ * The min_tso_segs is floored to 1 to avoid surprising conversion. Also,
+ * BPF callers may pass mss_now == 0. In that case the function returns the
+ * sanitized min_tso_segs value and skips autosizing.
  */
-static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
-			    int min_tso_segs)
+__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
+				 int min_tso_segs)
 {
+	u32 min_tso = max(min_tso_segs, 1);
 	unsigned long bytes;
 	u32 r;
 
+	if (unlikely(!mss_now))
+		return min_tso;
+
 	bytes = READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift);
 
 	r = tcp_min_rtt(tcp_sk(sk)) >> READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tso_rtt_log);
@@ -2267,8 +2275,9 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
 
 	bytes = min_t(unsigned long, bytes, sk->sk_gso_max_size);
 
-	return max_t(u32, bytes / mss_now, min_tso_segs);
+	return max_t(u32, bytes / mss_now, min_tso);
 }
+EXPORT_SYMBOL_GPL(tcp_tso_autosize);
 
 /* Return the number of segments we want in the skb we are transmitting.
  * See if congestion control module wants to decide; otherwise, autosize.
@@ -2276,14 +2285,13 @@ static u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
 static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)
 {
 	const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
-	u32 min_tso, tso_segs;
-
-	min_tso = ca_ops->min_tso_segs ?
-			ca_ops->min_tso_segs(sk) :
-			READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs);
+	u32 tso_segs;
 
-	tso_segs = tcp_tso_autosize(sk, mss_now, min_tso);
-	return min_t(u32, tso_segs, sk->sk_gso_max_segs);
+	tso_segs = ca_ops->tso_segs ?
+			ca_ops->tso_segs(sk, mss_now) :
+			tcp_tso_autosize(sk, mss_now,
+					 READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs));
+	return clamp_t(u32, tso_segs, 1, sk->sk_gso_max_segs);
 }
 
 /* Returns the portion of skb which can be sent right away */
diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
index 0a3e9d35bf6f0..58262e4903364 100644
--- a/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/tcp_ca_kfunc.c
@@ -10,7 +10,7 @@ extern u32 bbr_sndbuf_expand(struct sock *sk) __ksym;
 extern u32 bbr_undo_cwnd(struct sock *sk) __ksym;
 extern void bbr_cwnd_event_tx_start(struct sock *sk) __ksym;
 extern u32 bbr_ssthresh(struct sock *sk) __ksym;
-extern u32 bbr_min_tso_segs(struct sock *sk) __ksym;
+extern u32 bbr_tso_segs(struct sock *sk, u32 mss_now) __ksym;
 extern void bbr_set_state(struct sock *sk, u8 new_state) __ksym;
 
 extern void dctcp_init(struct sock *sk) __ksym;
@@ -90,9 +90,9 @@ u32 BPF_PROG(ssthresh, struct sock *sk)
 }
 
 SEC("struct_ops")
-u32 BPF_PROG(min_tso_segs, struct sock *sk)
+u32 BPF_PROG(tso_segs, struct sock *sk, u32 mss_now)
 {
-	return bbr_min_tso_segs(sk);
+	return bbr_tso_segs(sk, mss_now);
 }
 
 SEC("struct_ops")
@@ -120,7 +120,7 @@ struct tcp_congestion_ops tcp_ca_kfunc = {
 	.cwnd_event	= (void *)cwnd_event,
 	.cwnd_event_tx_start = (void *)cwnd_event_tx_start,
 	.ssthresh	= (void *)ssthresh,
-	.min_tso_segs	= (void *)min_tso_segs,
+	.tso_segs	= (void *)tso_segs,
 	.set_state	= (void *)set_state,
 	.pkts_acked     = (void *)pkts_acked,
 	.name		= "tcp_ca_kfunc",

25/3 2026/09/01 01:32 llm kmsan-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 5466
							output: 21
							thoughts: 868
						

Thoughts:
**KMSAN Fuzzing Session Assessment**

Okay, let's break down this patch and figure out if we need to throw a dedicated KMSAN fuzzing session at it. My initial thought is that it's probably okay, but we should always be thorough.

First, the patch itself refactors the `min_tso_segs` hook within the TCP congestion control ops. Specifically, it's changing the function signature from `u32 (*min_tso_segs)(struct sock *sk)` to `u32 (*tso_segs)(struct sock *sk, u32 mss_now)`. Basically, they're adding `mss_now` to the parameters. Looking at the included files, it looks like they're updating the definitions, the BPF kfunc checks, and the selftest to match this new signature. The important thing is that `bbr_min_tso_segs` is getting updated accordingly. We also have `tcp_tso_autosize`, which appears to be a helper function used in this whole process.

Now for the KMSAN risks... Let's see.

*   **Memory Allocations:** This doesn't seem to introduce any new allocations, which is good.
*   **Uninitialized Variables:** I'm not seeing any stack or heap variables that aren't properly initialized. The `mss_now` is passed as a value, so that should be safe.
*   **Userspace Exposure:** The `tcp_congestion_ops` struct is kernel-internal and also a BPF struct_ops, so that's not a concern.
*   **Buffer Operations:** No modifications to buffers, `copy_to_user`, `put_user`, netlink skbs, or socket options, which simplifies things.
*   **Bounds Checking/Data Lengths:** It's calculating TSO segment counts for packet segmentation. This is usually where we find issues, but it appears safe here.
*   **Branching:** No branching seems to be based on potentially uninitialized variables.

So far, it looks clean. But just to be extra sure, I'm going to run `grepper` and double-check to make sure we're not missing any usage of these hooks that could be affected by this change, especially with other congestion control modules. I want to see if anything else is using either `min_tso_segs` or `tso_segs`, just to verify that. All in all, my gut feeling is that this is a relatively safe patch from a KMSAN perspective, but verifying this with the grepper search is the correct final step.



26/3 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "min_tso_segs"
}

Results:
{
  "Output": "Documentation/networking/ip-sysctl.rst=1087=tcp_timestamps - INTEGER\n--\nDocumentation/networking/ip-sysctl.rst-1096-\nDocumentation/networking/ip-sysctl.rst:1097:tcp_min_tso_segs - INTEGER\nDocumentation/networking/ip-sysctl.rst-1098-\tMinimal number of segments per TSO frame.\n--\nDocumentation/networking/net_cachelines/netns_ipv4_sysctl.rst=114=int                             sysctl_tcp_min_rtt_wlen                      read_mostly                             tcp_ack_update_rt...\nDocumentation/networking/net_cachelines/netns_ipv4_sysctl.rst:115:u8                              sysctl_tcp_min_tso_segs                                                              unlikely(icsk_ca_...\nDocumentation/networking/net_cachelines/netns_ipv4_sysctl.rst-116-u8                              sysctl_tcp_tso_rtt_log                       read_mostly                             tcp_tso_autosize\n--\ninclude/net/netns/ipv4.h=55=struct netns_ipv4 {\n--\ninclude/net/netns/ipv4.h-225-\tint sysctl_tcp_challenge_ack_limit;\ninclude/net/netns/ipv4.h:226:\tu8 sysctl_tcp_min_tso_segs;\ninclude/net/netns/ipv4.h-227-\tu8 sysctl_tcp_reflect_tos;\n--\ninclude/net/tcp.h=827=u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\ninclude/net/tcp.h:828:\t\t     int min_tso_segs);\ninclude/net/tcp.h-829-\n--\nnet/ipv4/sysctl_net_ipv4.c=627=static const struct ctl_table ipv4_net_table[] = {\n--\nnet/ipv4/sysctl_net_ipv4.c-1393-\t{\nnet/ipv4/sysctl_net_ipv4.c:1394:\t\t.procname\t= \"tcp_min_tso_segs\",\nnet/ipv4/sysctl_net_ipv4.c:1395:\t\t.data\t\t= \u0026init_net.ipv4.sysctl_tcp_min_tso_segs,\nnet/ipv4/sysctl_net_ipv4.c-1396-\t\t.maxlen\t\t= sizeof(u8),\n--\nnet/ipv4/tcp_bbr.c=287=static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)\n--\nnet/ipv4/tcp_bbr.c-298-\nnet/ipv4/tcp_bbr.c:299:/* override sysctl_tcp_min_tso_segs */\nnet/ipv4/tcp_bbr.c:300:static u32 bbr_min_tso_segs(struct sock *sk)\nnet/ipv4/tcp_bbr.c-301-{\n--\nnet/ipv4/tcp_bbr.c=305=__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, u32 mss_now)\n--\nnet/ipv4/tcp_bbr.c-307-\tif (unlikely(!mss_now))\nnet/ipv4/tcp_bbr.c:308:\t\treturn bbr_min_tso_segs(sk);\nnet/ipv4/tcp_bbr.c:309:\treturn tcp_tso_autosize(sk, mss_now, bbr_min_tso_segs(sk));\nnet/ipv4/tcp_bbr.c-310-}\n--\nnet/ipv4/tcp_bbr.c=312=static u32 bbr_tso_segs_goal(struct sock *sk)\n--\nnet/ipv4/tcp_bbr.c-322-\t\t      GSO_LEGACY_MAX_SIZE - 1 - MAX_TCP_HEADER);\nnet/ipv4/tcp_bbr.c:323:\tsegs = max_t(u32, bytes / tp-\u003emss_cache, bbr_min_tso_segs(sk));\nnet/ipv4/tcp_bbr.c-324-\n--\nnet/ipv4/tcp_ipv4.c=3438=static int __net_init tcp_sk_init(struct net *net)\n--\nnet/ipv4/tcp_ipv4.c-3495-\nnet/ipv4/tcp_ipv4.c:3496:\tnet-\u003eipv4.sysctl_tcp_min_tso_segs = 2;\nnet/ipv4/tcp_ipv4.c-3497-\tnet-\u003eipv4.sysctl_tcp_tso_rtt_log = 9;  /* 2^9 = 512 usec */\n--\nnet/ipv4/tcp_output.c=2234=static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,\n--\nnet/ipv4/tcp_output.c-2255- *\nnet/ipv4/tcp_output.c:2256: * The min_tso_segs is floored to 1 to avoid surprising conversion. Also,\nnet/ipv4/tcp_output.c-2257- * BPF callers may pass mss_now == 0. In that case the function returns the\nnet/ipv4/tcp_output.c:2258: * sanitized min_tso_segs value and skips autosizing.\nnet/ipv4/tcp_output.c-2259- */\nnet/ipv4/tcp_output.c=2260=__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,\nnet/ipv4/tcp_output.c:2261:\t\t\t\t int min_tso_segs)\nnet/ipv4/tcp_output.c-2262-{\nnet/ipv4/tcp_output.c:2263:\tu32 min_tso = max(min_tso_segs, 1);\nnet/ipv4/tcp_output.c-2264-\tunsigned long bytes;\n--\nnet/ipv4/tcp_output.c=2285=static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\n--\nnet/ipv4/tcp_output.c-2292-\t\t\ttcp_tso_autosize(sk, mss_now,\nnet/ipv4/tcp_output.c:2293:\t\t\t\t\t READ_ONCE(sock_net(sk)-\u003eipv4.sysctl_tcp_min_tso_segs));\nnet/ipv4/tcp_output.c-2294-\treturn clamp_t(u32, tso_segs, 1, sk-\u003esk_gso_max_segs);\n--\ntools/testing/selftests/net/big_tcp_tunnels.sh=32=setup() {\n--\ntools/testing/selftests/net/big_tcp_tunnels.sh-52-\ntools/testing/selftests/net/big_tcp_tunnels.sh:53:\tDEFAULT_TCP_MIN_TSO_SEGS=$(ip netns exec \"$CLIENT_NS\" sysctl -n net.ipv4.tcp_min_tso_segs)\ntools/testing/selftests/net/big_tcp_tunnels.sh-54-}\n--\ntools/testing/selftests/net/big_tcp_tunnels.sh=111=do_test() {\n--\ntools/testing/selftests/net/big_tcp_tunnels.sh-140-\tif [ \"$3\" != 'on' ] \u0026\u0026 [ \"$KSFT_MACHINE_SLOW\" = yes ]; then\ntools/testing/selftests/net/big_tcp_tunnels.sh:141:\t\techo 'Slow configuration; increasing net.ipv4.tcp_min_tso_segs and initcwnd'\ntools/testing/selftests/net/big_tcp_tunnels.sh:142:\t\tip netns exec \"$CLIENT_NS\" sysctl -w net.ipv4.tcp_min_tso_segs=52\ntools/testing/selftests/net/big_tcp_tunnels.sh-143-\t\tif [ \"$2\" = 4 ]; then\n--\ntools/testing/selftests/net/big_tcp_tunnels.sh-151-\t\tip netns exec \"$CLIENT_NS\" \\\ntools/testing/selftests/net/big_tcp_tunnels.sh:152:\t\t    sysctl -w net.ipv4.tcp_min_tso_segs=\"$DEFAULT_TCP_MIN_TSO_SEGS\"\ntools/testing/selftests/net/big_tcp_tunnels.sh-153-\tfi\n--\ntools/testing/selftests/net/packetdrill/tcp_blocking_blocking-write.pkt-5-`./defaults.sh\ntools/testing/selftests/net/packetdrill/tcp_blocking_blocking-write.pkt:6:./set_sysctls.py /proc/sys/net/ipv4/tcp_min_tso_segs=10\ntools/testing/selftests/net/packetdrill/tcp_blocking_blocking-write.pkt-7-`\n--\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-idle.pkt-6-./set_sysctls.py /proc/sys/net/ipv4/tcp_slow_start_after_idle=1 \\\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-idle.pkt:7:\t\t /proc/sys/net/ipv4/tcp_min_tso_segs=10`\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-idle.pkt-8-\n--\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-win-update.pkt-6-./set_sysctls.py /proc/sys/net/ipv4/tcp_slow_start_after_idle=1 \\\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-win-update.pkt:7:\t\t /proc/sys/net/ipv4/tcp_min_tso_segs=10`\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-after-win-update.pkt-8-\n--\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-fq-ack-per-2pkt.pkt=11=sysctl -q net/ipv4/tcp_pacing_ss_ratio=200\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-fq-ack-per-2pkt.pkt:12:sysctl -e -q net.ipv4.tcp_min_tso_segs=2`\ntools/testing/selftests/net/packetdrill/tcp_slow_start_slow-start-fq-ack-per-2pkt.pkt-13-\n--\ntools/testing/selftests/net/packetdrill/tcp_timestamping_tcp_tx_timestamp_bug.pkt-8-`./defaults.sh\ntools/testing/selftests/net/packetdrill/tcp_timestamping_tcp_tx_timestamp_bug.pkt:9:sysctl -q net.ipv4.tcp_min_tso_segs=70\ntools/testing/selftests/net/packetdrill/tcp_timestamping_tcp_tx_timestamp_bug.pkt-10-`\n"
}

27/3 2026/09/01 01:32 llm kmsan-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 9881
							output: 32
							thoughts: 33
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach that query, as if it were my thought process:

**Diving into `tcp_tso_segs` in `tcp_output.c`**

Alright, time to get my hands dirty. My instinct is telling me to examine how `tcp_tso_segs` is called and utilized within `net/ipv4/tcp_output.c`. I need to understand its role in the TCP output path. What data structures is it manipulating? What are the implications of its operation on performance, especially with TSO enabled? I need to quickly identify the points where this function is called, and what the surrounding context is. Is it part of the initial segment creation, or is it involved in some kind of retransmission or adjustment? Understanding its place in the overall flow is the key to assessing its function. I'll be looking for any potential optimization opportunities, or perhaps spotting potential bottlenecks. Let's see what the code reveals!



28/3 2026/09/01 01:32 tool grepper
0m Args:
{
  "Expression": "tcp_tso_segs",
  "PathPrefix": "net/ipv4/"
}

Results:
{
  "Output": "net/ipv4/tcp_output.c=2280=EXPORT_SYMBOL_GPL(tcp_tso_autosize);\n--\nnet/ipv4/tcp_output.c-2284- */\nnet/ipv4/tcp_output.c:2285:static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)\nnet/ipv4/tcp_output.c-2286-{\n--\nnet/ipv4/tcp_output.c=2972=static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,\n--\nnet/ipv4/tcp_output.c-2999-\nnet/ipv4/tcp_output.c:3000:\tmax_segs = tcp_tso_segs(sk, mss_now);\nnet/ipv4/tcp_output.c-3001-\twhile ((skb = tcp_send_head(sk))) {\n--\nnet/ipv4/tcp_output.c=3733=void tcp_xmit_retransmit_queue(struct sock *sk)\n--\nnet/ipv4/tcp_output.c-3746-\tskb = tp-\u003eretransmit_skb_hint ?: rtx_head;\nnet/ipv4/tcp_output.c:3747:\tmax_segs = tcp_tso_segs(sk, tcp_current_mss(sk));\nnet/ipv4/tcp_output.c-3748-\tskb_rbtree_walk_from(skb) {\n"
}

29/3 2026/09/01 01:32 llm kmsan-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 10561
							output: 199
							thoughts: 417
						

Thoughts:
**KMSAN Assessment: No Concerns Here**

Okay, so I've looked over these changes related to the TCP congestion control callbacks and I'm feeling pretty confident about the KMSAN situation. The core of it is the refactoring of the congestion control ops. We're moving from `min_tso_segs` to a `tso_segs` callback. This makes sense; it lets congestion control modules like BBR and BPF CA calculate the TSO segment count based on the current MSS, which gives us more flexibility. We are also exposing `tcp_tso_autosize` as a BPF kfunc and adding some clamping and sanitization.

Here's the breakdown of why this *shouldn't* trigger any KMSAN flags:

*   **No Uninitialized Memory Issues:** This patch isn't creating, reading, writing, or leaking uninitialized memory. That's the key. KMSAN is all about detecting those scenarios where the system might use data before it's been properly initialized. That doesn't appear to be happening here.
*   **Scalar Data Only:** The inputs and outputs are just integers - `u32`, `unsigned int`. The potential for weirdness with uninitialized memory is just vanishingly small. We're talking about scalar values passed by value.
*   **Safety Checks:** We've got clamping and bounds checks in place. That adds a layer of protection that the value is always in a known good state.

KASAN (Kernel Address Sanitizer) is a separate issue, and that's the more appropriate tool for the sorts of errors you'd encounter here if there were any. Things like out-of-bounds access or math/logic bugs. But that's not what KMSAN is for.

So, I'm comfortable calling this `NeedsKMSAN` as `false`. We can call `set-results`. No need to burn any cycles on a KMSAN fuzzing session. This patch looks clean from an uninitialized memory perspective.



30/3 2026/09/01 01:32 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch refactors the TCP congestion control ops interface by replacing the `min_tso_segs` callback with `tso_segs(struct sock *sk, u32 mss_now)`, updates BBR and BPF congestion control hooks, and exports `tcp_tso_autosize` as a BPF kfunc.\n\nAll modified and added functions operate on scalar integer values passed by value (`u32`, `unsigned int`, pointers to fully initialized struct `sock`). No new memory allocations, stack/heap structures, or data copies to user-space (such as `copy_to_user`, netlink attributes, or ioctl returns) are introduced or modified. There is no risk of uninitialized memory reads or information leaks to user space. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch refactors the TCP congestion control ops interface by replacing the `min_tso_segs` callback with `tso_segs(struct sock *sk, u32 mss_now)`, updates BBR and BPF congestion control hooks, and exports `tcp_tso_autosize` as a BPF kfunc.\n\nAll modified and added functions operate on scalar integer values passed by value (`u32`, `unsigned int`, pointers to fully initialized struct `sock`). No new memory allocations, stack/heap structures, or data copies to user-space (such as `copy_to_user`, netlink attributes, or ioctl returns) are introduced or modified. There is no risk of uninitialized memory reads or information leaks to user space. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

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)