AI Trajectory


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

Results:
{
  "EnableConfigs": [
    "VIRTIO_VSOCKETS",
    "VSOCKETS_LOOPBACK"
  ],
  "FocusSymbols": [
    "virtio_transport_collapse_rx_queue",
    "virtio_transport_collapse_size",
    "virtio_transport_can_collapse"
  ],
  "Reasoning": "The patch introduces a new packet collapsing mechanism in the virtio-vsock receive path to prevent connection resets under memory pressure. This is a functional change in the core vsock logic that can be triggered by sending many small packets, making it a good target for fuzzing.",
  "WorthFuzzing": true
}

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

Results:
{
  "PatchDiff": "commit 08e58fff3e10f118e01b613ddcf7826f406df62d\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Thu Jul 9 01:09:14 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c\nindex 09475007165b36..8becad81279c86 100644\n--- a/net/vmw_vsock/virtio_transport_common.c\n+++ b/net/vmw_vsock/virtio_transport_common.c\n@@ -26,6 +26,13 @@\n /* Threshold for detecting small packets to copy */\n #define GOOD_COPY_LEN  128\n \n+/* Max payload that can be collapsed into a single linear skb, using the same\n+ * allocation threshold as virtio_vsock_alloc_skb() to avoid adding pressure\n+ * on the page allocator.\n+ */\n+#define MAX_COLLAPSE_LEN \\\n+\tSKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM, PAGE_ALLOC_COSTLY_ORDER)\n+\n static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,\n \t\t\t\t\t       bool cancel_timeout);\n static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs);\n@@ -420,6 +427,145 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,\n \treturn ret;\n }\n \n+static bool virtio_transport_can_collapse(struct sk_buff *skb)\n+{\n+\t/* skbs that are partially consumed, mark a SEQPACKET message boundary,\n+\t * or are already large enough should not be collapsed: they either\n+\t * need special accounting, carry protocol state, or already have a\n+\t * good data-to-overhead ratio.\n+\t */\n+\tif (VIRTIO_VSOCK_SKB_CB(skb)-\u003eoffset)\n+\t\treturn false;\n+\tif (le32_to_cpu(virtio_vsock_hdr(skb)-\u003eflags) \u0026 VIRTIO_VSOCK_SEQ_EOM)\n+\t\treturn false;\n+\tif (skb-\u003elen \u003e= MAX_COLLAPSE_LEN)\n+\t\treturn false;\n+\treturn true;\n+}\n+\n+/* Iterate through the packets in the queue starting from the current skb to\n+ * count the number of bytes we can collapse.\n+ */\n+static unsigned int\n+virtio_transport_collapse_size(struct sk_buff *skb, struct sk_buff_head *queue)\n+{\n+\tunsigned int target = skb-\u003elen - VIRTIO_VSOCK_SKB_CB(skb)-\u003eoffset;\n+\n+\twhile ((skb = skb_peek_next(skb, queue)) \u0026\u0026\n+\t       virtio_transport_can_collapse(skb)) {\n+\t\tunsigned int len = skb-\u003elen - VIRTIO_VSOCK_SKB_CB(skb)-\u003eoffset;\n+\n+\t\tif (len \u003e MAX_COLLAPSE_LEN - target)\n+\t\t\treturn target;\n+\n+\t\ttarget += len;\n+\t}\n+\n+\treturn target;\n+}\n+\n+/* Called under lock_sock to compact the receive queue by merging small skbs.\n+ * @min_to_free: minimum number of skbs to eliminate from the queue. May free\n+ *               more to fill each collapsed skb to capacity.\n+ */\n+static void\n+virtio_transport_collapse_rx_queue(struct virtio_vsock_sock *vvs,\n+\t\t\t\t   u32 min_to_free)\n+{\n+\tstruct sk_buff *skb, *next_skb, *new_skb = NULL;\n+\tstruct sk_buff_head new_queue;\n+\tu32 saved = 0;\n+\n+\t__skb_queue_head_init(\u0026new_queue);\n+\n+\tskb_queue_walk_safe(\u0026vvs-\u003erx_queue, skb, next_skb) {\n+\t\tstruct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);\n+\t\tu32 src_off = VIRTIO_VSOCK_SKB_CB(skb)-\u003eoffset;\n+\t\tu32 src_len = skb-\u003elen - src_off;\n+\t\tbool keep;\n+\n+\t\tkeep = !virtio_transport_can_collapse(skb);\n+\t\tif (keep) {\n+\t\t\t/* Finalize pending collapsed skb to preserve packet\n+\t\t\t * ordering.\n+\t\t\t */\n+\t\t\tif (new_skb) {\n+\t\t\t\t__skb_queue_tail(\u0026new_queue, new_skb);\n+\t\t\t\tnew_skb = NULL;\n+\t\t\t\tsaved--;\n+\t\t\t}\n+\t\t\tgoto next;\n+\t\t}\n+\n+\t\t/* Finalize if this packet won't fit in the remaining tailroom,\n+\t\t * so we can allocate a right-sized new_skb.\n+\t\t */\n+\t\tif (new_skb \u0026\u0026 src_len \u003e skb_tailroom(new_skb)) {\n+\t\t\t__skb_queue_tail(\u0026new_queue, new_skb);\n+\t\t\tnew_skb = NULL;\n+\t\t\tsaved--;\n+\t\t}\n+\n+\t\tif (!new_skb) {\n+\t\t\tunsigned int alloc_size;\n+\n+\t\t\t/* Check after finalizing to opportunistically fill\n+\t\t\t * each collapsed skb to capacity, merging more skbs\n+\t\t\t * than strictly required.\n+\t\t\t */\n+\t\t\tif (saved \u003e= min_to_free)\n+\t\t\t\tbreak;\n+\n+\t\t\talloc_size = virtio_transport_collapse_size(skb, \u0026vvs-\u003erx_queue);\n+\n+\t\t\t/* Only this skb's data is eligible, nothing to merge\n+\t\t\t * with. Keep as-is.\n+\t\t\t */\n+\t\t\tif (alloc_size \u003c= src_len) {\n+\t\t\t\tkeep = true;\n+\t\t\t\tgoto next;\n+\t\t\t}\n+\n+\t\t\tnew_skb = virtio_vsock_alloc_linear_skb(alloc_size +\n+\t\t\t\t\tVIRTIO_VSOCK_SKB_HEADROOM, GFP_KERNEL);\n+\t\t\tif (!new_skb)\n+\t\t\t\tbreak;\n+\n+\t\t\tmemcpy(virtio_vsock_hdr(new_skb), hdr,\n+\t\t\t       sizeof(struct virtio_vsock_hdr));\n+\t\t\tvirtio_vsock_hdr(new_skb)-\u003elen = 0;\n+\t\t}\n+\n+\t\t/* Cannot fail since src_off/src_len are within bounds, but if\n+\t\t * it does, discard new_skb to avoid queuing corrupted data.\n+\t\t */\n+\t\tif (WARN_ON_ONCE(skb_copy_bits(skb, src_off,\n+\t\t\t\t\t       skb_put(new_skb, src_len),\n+\t\t\t\t\t       src_len))) {\n+\t\t\tkfree_skb(new_skb);\n+\t\t\tnew_skb = NULL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tle32_add_cpu(\u0026virtio_vsock_hdr(new_skb)-\u003elen, src_len);\n+\t\tvirtio_vsock_hdr(new_skb)-\u003eflags |= hdr-\u003eflags;\n+\n+next:\n+\t\t__skb_unlink(skb, \u0026vvs-\u003erx_queue);\n+\t\tif (keep) {\n+\t\t\t__skb_queue_tail(\u0026new_queue, skb);\n+\t\t} else {\n+\t\t\tconsume_skb(skb);\n+\t\t\tsaved++;\n+\t\t}\n+\t}\n+\n+\tif (new_skb)\n+\t\t__skb_queue_tail(\u0026new_queue, new_skb);\n+\n+\tskb_queue_splice(\u0026new_queue, \u0026vvs-\u003erx_queue);\n+}\n+\n static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,\n \t\t\t\t\tu32 len)\n {\n@@ -1354,12 +1500,29 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,\n {\n \tstruct virtio_vsock_sock *vvs = vsk-\u003etrans;\n \tbool can_enqueue, free_pkt = false;\n+\tu32 len, queue_max, queue_len;\n \tstruct virtio_vsock_hdr *hdr;\n-\tu32 len;\n \n \thdr = virtio_vsock_hdr(skb);\n \tlen = le32_to_cpu(hdr-\u003elen);\n \n+\t/* virtio_transport_inc_rx_pkt() rejects packets when the per-skb\n+\t * overhead (skb_queue_len * SKB_TRUESIZE(0)) exceeds buf_alloc.\n+\t * Proactively collapse the queue before that happens.\n+\t * No rx_lock needed: lock_sock is held by caller, preventing\n+\t * concurrent enqueue or dequeue.\n+\t */\n+\tqueue_max = vvs-\u003ebuf_alloc / SKB_TRUESIZE(0);\n+\tqueue_len = skb_queue_len(\u0026vvs-\u003erx_queue);\n+\tif (queue_len \u003e= queue_max) {\n+\t\t/* Walking a large queue may take a significant amount of time\n+\t\t * and cache misses, causing traffic burstiness. Limit the\n+\t\t * collapse to freeing room for this packet and the next one.\n+\t\t * It may free more to fill each collapsed skb to capacity.\n+\t\t */\n+\t\tvirtio_transport_collapse_rx_queue(vvs, queue_len + 2 - queue_max);\n+\t}\n+\n \tspin_lock_bh(\u0026vvs-\u003erx_lock);\n \n \tcan_enqueue = virtio_transport_inc_rx_pkt(vvs, len);\ndiff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c\nindex 76be0e4a7f0ee6..b4ff9f946565b8 100644\n--- a/tools/testing/vsock/vsock_test.c\n+++ b/tools/testing/vsock/vsock_test.c\n@@ -2347,6 +2347,88 @@ static void test_stream_tx_credit_bounds_server(const struct test_opts *opts)\n \tclose(fd);\n }\n \n+/* Test that many small packets don't cause a connection reset under pressure\n+ * and that data integrity is preserved.  Packet sizes vary randomly between\n+ * 129 and 512 bytes, above GOOD_COPY_LEN (128) to bypass in-place coalescing\n+ * in recv_enqueue, forcing each one into its own skb.  Without receive queue\n+ * collapsing, the per-skb overhead eventually exceeds buf_alloc and the\n+ * connection is reset.\n+ */\n+#define COLLAPSE_PKT_MIN 129\n+#define COLLAPSE_PKT_MAX 512\n+#define COLLAPSE_TOTAL (2 * 1024 * 1024)\n+\n+static void test_stream_collapse_client(const struct test_opts *opts)\n+{\n+\tunsigned char *data;\n+\tunsigned long hash;\n+\tsize_t offset = 0;\n+\tint i, fd;\n+\n+\tdata = malloc(COLLAPSE_TOTAL);\n+\tif (!data) {\n+\t\tperror(\"malloc\");\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\tfor (i = 0; i \u003c COLLAPSE_TOTAL; i++)\n+\t\tdata[i] = rand() \u0026 0xff;\n+\n+\tfd = vsock_stream_connect(opts-\u003epeer_cid, opts-\u003epeer_port);\n+\tif (fd \u003c 0) {\n+\t\tperror(\"connect\");\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\twhile (offset \u003c COLLAPSE_TOTAL) {\n+\t\tsize_t pkt_size = COLLAPSE_PKT_MIN +\n+\t\t\trand() % (COLLAPSE_PKT_MAX - COLLAPSE_PKT_MIN + 1);\n+\n+\t\tpkt_size = min(pkt_size, COLLAPSE_TOTAL - offset);\n+\n+\t\tsend_buf(fd, data + offset, pkt_size, 0, pkt_size);\n+\t\toffset += pkt_size;\n+\t}\n+\n+\thash = hash_djb2(data, COLLAPSE_TOTAL);\n+\tcontrol_writeulong(hash);\n+\n+\tfree(data);\n+\tclose(fd);\n+}\n+\n+static void test_stream_collapse_server(const struct test_opts *opts)\n+{\n+\tunsigned long hash, remote_hash;\n+\tunsigned char *data;\n+\tint fd;\n+\n+\tdata = malloc(COLLAPSE_TOTAL);\n+\tif (!data) {\n+\t\tperror(\"malloc\");\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\tfd = vsock_stream_accept(VMADDR_CID_ANY, opts-\u003epeer_port, NULL);\n+\tif (fd \u003c 0) {\n+\t\tperror(\"accept\");\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\trecv_buf(fd, data, COLLAPSE_TOTAL, 0, COLLAPSE_TOTAL);\n+\n+\thash = hash_djb2(data, COLLAPSE_TOTAL);\n+\tremote_hash = control_readulong();\n+\tif (hash != remote_hash) {\n+\t\tfprintf(stderr, \"hash mismatch: local %lu remote %lu\\n\",\n+\t\t\thash, remote_hash);\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\tfree(data);\n+\tclose(fd);\n+}\n+\n static struct test_case test_cases[] = {\n \t{\n \t\t.name = \"SOCK_STREAM connection reset\",\n@@ -2546,6 +2628,11 @@ static struct test_case test_cases[] = {\n \t\t.run_client = test_stream_msg_peek_client,\n \t\t.run_server = test_stream_peek_after_recv_server,\n \t},\n+\t{\n+\t\t.name = \"SOCK_STREAM small packets backpressure\",\n+\t\t.run_client = test_stream_collapse_client,\n+\t\t.run_server = test_stream_collapse_server,\n+\t},\n \t{},\n };\n \n"
}

2/1 2026/07/09 01:09 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "VIRTIO_VSOCKETS",
    "VSOCKETS_LOOPBACK"
  ],
  "FocusSymbols": [
    "virtio_transport_collapse_rx_queue",
    "virtio_transport_collapse_size",
    "virtio_transport_can_collapse"
  ],
  "Reasoning": "The patch introduces a new packet collapsing mechanism in the virtio-vsock receive path to prevent connection resets under memory pressure. This is a functional change in the core vsock logic that can be triggered by sending many small packets, making it a good target for fuzzing.",
  "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).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


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

Prompt:
For your convenience, here is the diff of the changes:
commit 08e58fff3e10f118e01b613ddcf7826f406df62d
Author: syz-cluster <triage@syzkaller.com>
Date:   Thu Jul 9 01:09:14 2026 +0000

    syz-cluster: applied patch under review

diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 09475007165b36..8becad81279c86 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -26,6 +26,13 @@
 /* Threshold for detecting small packets to copy */
 #define GOOD_COPY_LEN  128
 
+/* Max payload that can be collapsed into a single linear skb, using the same
+ * allocation threshold as virtio_vsock_alloc_skb() to avoid adding pressure
+ * on the page allocator.
+ */
+#define MAX_COLLAPSE_LEN \
+	SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM, PAGE_ALLOC_COSTLY_ORDER)
+
 static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
 					       bool cancel_timeout);
 static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs);
@@ -420,6 +427,145 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
 	return ret;
 }
 
+static bool virtio_transport_can_collapse(struct sk_buff *skb)
+{
+	/* skbs that are partially consumed, mark a SEQPACKET message boundary,
+	 * or are already large enough should not be collapsed: they either
+	 * need special accounting, carry protocol state, or already have a
+	 * good data-to-overhead ratio.
+	 */
+	if (VIRTIO_VSOCK_SKB_CB(skb)->offset)
+		return false;
+	if (le32_to_cpu(virtio_vsock_hdr(skb)->flags) & VIRTIO_VSOCK_SEQ_EOM)
+		return false;
+	if (skb->len >= MAX_COLLAPSE_LEN)
+		return false;
+	return true;
+}
+
+/* Iterate through the packets in the queue starting from the current skb to
+ * count the number of bytes we can collapse.
+ */
+static unsigned int
+virtio_transport_collapse_size(struct sk_buff *skb, struct sk_buff_head *queue)
+{
+	unsigned int target = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
+
+	while ((skb = skb_peek_next(skb, queue)) &&
+	       virtio_transport_can_collapse(skb)) {
+		unsigned int len = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
+
+		if (len > MAX_COLLAPSE_LEN - target)
+			return target;
+
+		target += len;
+	}
+
+	return target;
+}
+
+/* Called under lock_sock to compact the receive queue by merging small skbs.
+ * @min_to_free: minimum number of skbs to eliminate from the queue. May free
+ *               more to fill each collapsed skb to capacity.
+ */
+static void
+virtio_transport_collapse_rx_queue(struct virtio_vsock_sock *vvs,
+				   u32 min_to_free)
+{
+	struct sk_buff *skb, *next_skb, *new_skb = NULL;
+	struct sk_buff_head new_queue;
+	u32 saved = 0;
+
+	__skb_queue_head_init(&new_queue);
+
+	skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) {
+		struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
+		u32 src_off = VIRTIO_VSOCK_SKB_CB(skb)->offset;
+		u32 src_len = skb->len - src_off;
+		bool keep;
+
+		keep = !virtio_transport_can_collapse(skb);
+		if (keep) {
+			/* Finalize pending collapsed skb to preserve packet
+			 * ordering.
+			 */
+			if (new_skb) {
+				__skb_queue_tail(&new_queue, new_skb);
+				new_skb = NULL;
+				saved--;
+			}
+			goto next;
+		}
+
+		/* Finalize if this packet won't fit in the remaining tailroom,
+		 * so we can allocate a right-sized new_skb.
+		 */
+		if (new_skb && src_len > skb_tailroom(new_skb)) {
+			__skb_queue_tail(&new_queue, new_skb);
+			new_skb = NULL;
+			saved--;
+		}
+
+		if (!new_skb) {
+			unsigned int alloc_size;
+
+			/* Check after finalizing to opportunistically fill
+			 * each collapsed skb to capacity, merging more skbs
+			 * than strictly required.
+			 */
+			if (saved >= min_to_free)
+				break;
+
+			alloc_size = virtio_transport_collapse_size(skb, &vvs->rx_queue);
+
+			/* Only this skb's data is eligible, nothing to merge
+			 * with. Keep as-is.
+			 */
+			if (alloc_size <= src_len) {
+				keep = true;
+				goto next;
+			}
+
+			new_skb = virtio_vsock_alloc_linear_skb(alloc_size +
+					VIRTIO_VSOCK_SKB_HEADROOM, GFP_KERNEL);
+			if (!new_skb)
+				break;
+
+			memcpy(virtio_vsock_hdr(new_skb), hdr,
+			       sizeof(struct virtio_vsock_hdr));
+			virtio_vsock_hdr(new_skb)->len = 0;
+		}
+
+		/* Cannot fail since src_off/src_len are within bounds, but if
+		 * it does, discard new_skb to avoid queuing corrupted data.
+		 */
+		if (WARN_ON_ONCE(skb_copy_bits(skb, src_off,
+					       skb_put(new_skb, src_len),
+					       src_len))) {
+			kfree_skb(new_skb);
+			new_skb = NULL;
+			break;
+		}
+
+		le32_add_cpu(&virtio_vsock_hdr(new_skb)->len, src_len);
+		virtio_vsock_hdr(new_skb)->flags |= hdr->flags;
+
+next:
+		__skb_unlink(skb, &vvs->rx_queue);
+		if (keep) {
+			__skb_queue_tail(&new_queue, skb);
+		} else {
+			consume_skb(skb);
+			saved++;
+		}
+	}
+
+	if (new_skb)
+		__skb_queue_tail(&new_queue, new_skb);
+
+	skb_queue_splice(&new_queue, &vvs->rx_queue);
+}
+
 static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
 					u32 len)
 {
@@ -1354,12 +1500,29 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,
 {
 	struct virtio_vsock_sock *vvs = vsk->trans;
 	bool can_enqueue, free_pkt = false;
+	u32 len, queue_max, queue_len;
 	struct virtio_vsock_hdr *hdr;
-	u32 len;
 
 	hdr = virtio_vsock_hdr(skb);
 	len = le32_to_cpu(hdr->len);
 
+	/* virtio_transport_inc_rx_pkt() rejects packets when the per-skb
+	 * overhead (skb_queue_len * SKB_TRUESIZE(0)) exceeds buf_alloc.
+	 * Proactively collapse the queue before that happens.
+	 * No rx_lock needed: lock_sock is held by caller, preventing
+	 * concurrent enqueue or dequeue.
+	 */
+	queue_max = vvs->buf_alloc / SKB_TRUESIZE(0);
+	queue_len = skb_queue_len(&vvs->rx_queue);
+	if (queue_len >= queue_max) {
+		/* Walking a large queue may take a significant amount of time
+		 * and cache misses, causing traffic burstiness. Limit the
+		 * collapse to freeing room for this packet and the next one.
+		 * It may free more to fill each collapsed skb to capacity.
+		 */
+		virtio_transport_collapse_rx_queue(vvs, queue_len + 2 - queue_max);
+	}
+
 	spin_lock_bh(&vvs->rx_lock);
 
 	can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
index 76be0e4a7f0ee6..b4ff9f946565b8 100644
--- a/tools/testing/vsock/vsock_test.c
+++ b/tools/testing/vsock/vsock_test.c
@@ -2347,6 +2347,88 @@ static void test_stream_tx_credit_bounds_server(const struct test_opts *opts)
 	close(fd);
 }
 
+/* Test that many small packets don't cause a connection reset under pressure
+ * and that data integrity is preserved.  Packet sizes vary randomly between
+ * 129 and 512 bytes, above GOOD_COPY_LEN (128) to bypass in-place coalescing
+ * in recv_enqueue, forcing each one into its own skb.  Without receive queue
+ * collapsing, the per-skb overhead eventually exceeds buf_alloc and the
+ * connection is reset.
+ */
+#define COLLAPSE_PKT_MIN 129
+#define COLLAPSE_PKT_MAX 512
+#define COLLAPSE_TOTAL (2 * 1024 * 1024)
+
+static void test_stream_collapse_client(const struct test_opts *opts)
+{
+	unsigned char *data;
+	unsigned long hash;
+	size_t offset = 0;
+	int i, fd;
+
+	data = malloc(COLLAPSE_TOTAL);
+	if (!data) {
+		perror("malloc");
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 0; i < COLLAPSE_TOTAL; i++)
+		data[i] = rand() & 0xff;
+
+	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
+	if (fd < 0) {
+		perror("connect");
+		exit(EXIT_FAILURE);
+	}
+
+	while (offset < COLLAPSE_TOTAL) {
+		size_t pkt_size = COLLAPSE_PKT_MIN +
+			rand() % (COLLAPSE_PKT_MAX - COLLAPSE_PKT_MIN + 1);
+
+		pkt_size = min(pkt_size, COLLAPSE_TOTAL - offset);
+
+		send_buf(fd, data + offset, pkt_size, 0, pkt_size);
+		offset += pkt_size;
+	}
+
+	hash = hash_djb2(data, COLLAPSE_TOTAL);
+	control_writeulong(hash);
+
+	free(data);
+	close(fd);
+}
+
+static void test_stream_collapse_server(const struct test_opts *opts)
+{
+	unsigned long hash, remote_hash;
+	unsigned char *data;
+	int fd;
+
+	data = malloc(COLLAPSE_TOTAL);
+	if (!data) {
+		perror("malloc");
+		exit(EXIT_FAILURE);
+	}
+
+	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
+	if (fd < 0) {
+		perror("accept");
+		exit(EXIT_FAILURE);
+	}
+
+	recv_buf(fd, data, COLLAPSE_TOTAL, 0, COLLAPSE_TOTAL);
+
+	hash = hash_djb2(data, COLLAPSE_TOTAL);
+	remote_hash = control_readulong();
+	if (hash != remote_hash) {
+		fprintf(stderr, "hash mismatch: local %lu remote %lu\n",
+			hash, remote_hash);
+		exit(EXIT_FAILURE);
+	}
+
+	free(data);
+	close(fd);
+}
+
 static struct test_case test_cases[] = {
 	{
 		.name = "SOCK_STREAM connection reset",
@@ -2546,6 +2628,11 @@ static struct test_case test_cases[] = {
 		.run_client = test_stream_msg_peek_client,
 		.run_server = test_stream_peek_after_recv_server,
 	},
+	{
+		.name = "SOCK_STREAM small packets backpressure",
+		.run_client = test_stream_collapse_client,
+		.run_server = test_stream_collapse_server,
+	},
 	{},
 };
 

3/2 2026/07/09 01:09 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 5132
							output: 34
							thoughts: 227
						

Thoughts:
**Analyzing the Virtio-VSock Patch**

Okay, so I've got this patch here that’s tweaking `net/vmw_vsock/virtio_transport_common.c` and `tools/testing/vsock/vsock_test.c`. It looks like the main goal is to improve the handling of small packets in the virtio-vsock receive queue. Specifically, the patch aims to collapse these packets to prevent connection resets when things get heavy, likely due to the overhead of individual `skb` structures exceeding the available `buf_alloc`. The changes seem pretty focused, adding and modifying a few key functions: `virtio_transport_can_collapse`, `virtio_transport_collapse_size`, `virtio_transport_collapse_rx_queue`, and also modifying `virtio_transport_recv_enqueue` to call the collapsing queue function.

This is a pretty fundamental change to how virtio-vsock handles data reception, so definitely a candidate for thorough fuzzing. I'll want to get a good fuzzing campaign up and running to make sure we don’t introduce any regressions or corner-case bugs with this new logic.

Now, let's see how virtio-vsock is configured. I’ll use `grepper` to search the `Makefile` and `Kconfig` files under `net/vmw_vsock/` for configuration options that might affect this. Specifically, I need to know how these features are enabled or disabled, and what knobs are available to control their behavior. Getting a handle on the build configuration is always the first step.



4/2 2026/07/09 01:09 tool grepper
0m Args:
{
  "Expression": "virtio_transport_common",
  "PathPrefix": "net/vmw_vsock/"
}

Results:
{
  "Output": "net/vmw_vsock/Kconfig=29=config VSOCKETS_LOOPBACK\n--\nnet/vmw_vsock/Kconfig-35-\t  This module implements a loopback transport for Virtual Sockets,\nnet/vmw_vsock/Kconfig:36:\t  using vmw_vsock_virtio_transport_common.\nnet/vmw_vsock/Kconfig-37-\n--\nnet/vmw_vsock/Kconfig=66=config VIRTIO_VSOCKETS_COMMON\n--\nnet/vmw_vsock/Kconfig-70-\t  the virtio_vsock.  The module will be called\nnet/vmw_vsock/Kconfig:71:\t  vmw_vsock_virtio_transport_common.\nnet/vmw_vsock/Kconfig-72-\n--\nnet/vmw_vsock/Makefile=5=obj-$(CONFIG_VIRTIO_VSOCKETS) += vmw_vsock_virtio_transport.o\nnet/vmw_vsock/Makefile:6:obj-$(CONFIG_VIRTIO_VSOCKETS_COMMON) += vmw_vsock_virtio_transport_common.o\nnet/vmw_vsock/Makefile-7-obj-$(CONFIG_HYPERV_VSOCKETS) += hv_sock.o\n--\nnet/vmw_vsock/Makefile=18=vmw_vsock_virtio_transport-y += virtio_transport.o\nnet/vmw_vsock/Makefile-19-\nnet/vmw_vsock/Makefile:20:vmw_vsock_virtio_transport_common-y += virtio_transport_common.o\nnet/vmw_vsock/Makefile-21-\n--\nnet/vmw_vsock/virtio_transport_common.c-20-#define CREATE_TRACE_POINTS\nnet/vmw_vsock/virtio_transport_common.c:21:#include \u003ctrace/events/vsock_virtio_transport_common.h\u003e\nnet/vmw_vsock/virtio_transport_common.c-22-\n--\nnet/vmw_vsock/vsock_loopback.c-1-// SPDX-License-Identifier: GPL-2.0-only\nnet/vmw_vsock/vsock_loopback.c:2:/* loopback transport for vsock using virtio_transport_common APIs\nnet/vmw_vsock/vsock_loopback.c-3- *\n"
}

5/2 2026/07/09 01:09 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6342
							output: 37
							thoughts: 60
						

Thoughts:
**Examining the Virtual Sockets Configuration**

Okay, so I'm looking at the necessary configurations here. I see we have `VIRTIO_VSOCKETS_COMMON`, `VIRTIO_VSOCKETS`, and `VSOCKETS_LOOPBACK` flagged as relevant. My first instinct, as always, is to dive into the Kconfig files for a deeper understanding. Let's start with `net/vmw_vsock/Kconfig`, specifically focusing on how `VIRTIO_VSOCKETS_COMMON` is defined. This should give me a solid foundation for understanding the dependencies and implications of these settings. I need to see how these pieces fit together to ensure the vSockets implementation is correctly configured. This is fundamental to verifying its operation.



6/2 2026/07/09 01:09 tool grepper
0m Args:
{
  "Expression": "VIRTIO_VSOCKETS",
  "PathPrefix": "net/vmw_vsock/Kconfig"
}

Results:
{
  "Output": "net/vmw_vsock/Kconfig=29=config VSOCKETS_LOOPBACK\n--\nnet/vmw_vsock/Kconfig-32-\tdefault y\nnet/vmw_vsock/Kconfig:33:\tselect VIRTIO_VSOCKETS_COMMON\nnet/vmw_vsock/Kconfig-34-\thelp\n--\nnet/vmw_vsock/Kconfig=41=config VMWARE_VMCI_VSOCKETS\n--\nnet/vmw_vsock/Kconfig-52-\nnet/vmw_vsock/Kconfig:53:config VIRTIO_VSOCKETS\nnet/vmw_vsock/Kconfig-54-\ttristate \"virtio transport for Virtual Sockets\"\nnet/vmw_vsock/Kconfig-55-\tdepends on VSOCKETS \u0026\u0026 VIRTIO\nnet/vmw_vsock/Kconfig:56:\tselect VIRTIO_VSOCKETS_COMMON\nnet/vmw_vsock/Kconfig-57-\thelp\n--\nnet/vmw_vsock/Kconfig-65-\nnet/vmw_vsock/Kconfig:66:config VIRTIO_VSOCKETS_COMMON\nnet/vmw_vsock/Kconfig-67-\ttristate\n"
}

7/2 2026/07/09 01:09 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 6920
							output: 138
							thoughts: 307
						

Thoughts:
**My Analysis of VIRTIO_VSOCKETS Configuration**

Okay, let's break this down. My understanding is that `VIRTIO_VSOCKETS` and `VSOCKETS_LOOPBACK` both include `VIRTIO_VSOCKETS_COMMON`. Therefore, specifying either `VIRTIO_VSOCKETS` or `VSOCKETS_LOOPBACK` would be sufficient to enable the shared functionality.

Now, my focus is on optimization and potential fuzzing targets. My attention is drawn to `virtio_transport_collapse_rx_queue`, `virtio_transport_collapse_size`, and `virtio_transport_can_collapse`.

I'm thinking, is `virtio_transport_recv_enqueue` a potential performance bottleneck? It's definitely in the receive path, so it could be hot. However, the `virtio_transport_collapse_rx_queue` function itself is only called when the receive queue is large, making *it* an interesting target for fuzzing.

Let's quickly confirm if `virtio_transport_collapse_rx_queue` is static. Yes, it is! Given that it's static, I can directly focus on that one, which makes my job easier.

Hang on… I see that `virtio_transport_can_collapse` and `virtio_transport_collapse_size` are *also* static. This means I should include those in the analysis too – it’s good to have all the pieces.

Just to be thorough, I should re-examine the bigger picture. I recall `VSOCKETS` is the base configuration, and that `VIRTIO_VSOCKETS` and `VSOCKETS_LOOPBACK` are the options that specifically enable the virtio transport common elements.

Alright, that's the summary I need to move forward with the next steps.



8/2 2026/07/09 01:09 tool set-results
0m Args:
{
  "EnableConfigs": [
    "VIRTIO_VSOCKETS",
    "VSOCKETS_LOOPBACK"
  ],
  "FocusSymbols": [
    "virtio_transport_collapse_rx_queue",
    "virtio_transport_collapse_size",
    "virtio_transport_can_collapse"
  ],
  "Reasoning": "The patch introduces a new packet collapsing mechanism in the virtio-vsock receive path to prevent connection resets under memory pressure. This is a functional change in the core vsock logic that can be triggered by sending many small packets, making it a good target for fuzzing.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "VIRTIO_VSOCKETS",
    "VSOCKETS_LOOPBACK"
  ],
  "FocusSymbols": [
    "virtio_transport_collapse_rx_queue",
    "virtio_transport_collapse_size",
    "virtio_transport_can_collapse"
  ],
  "Reasoning": "The patch introduces a new packet collapsing mechanism in the virtio-vsock receive path to prevent connection resets under memory pressure. This is a functional change in the core vsock logic that can be triggered by sending many small packets, making it a good target for fuzzing.",
  "WorthFuzzing": true
}

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)