summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-05-21 13:14:04 +0200
committerPaolo Abeni <pabeni@redhat.com>2026-05-21 13:14:04 +0200
commit94e3dd6874bf04d5939bc8431b9f7852f3a4a121 (patch)
tree76b5f9b8ef84ca3225cc992d2a647342554d9e4f
parent0377bd2722c1891754cde2bc41de21bc34c50d6c (diff)
parentc6087c5aaad6d1b8be1a1a641e0a422218ade911 (diff)
Merge branch 'vsock-virtio-fix-skb-overhead-accounting-to-preserve-full-buf_alloc'
Stefano Garzarella says: ==================== vsock/virtio: fix skb overhead accounting to preserve full buf_alloc Patch 1 resets the connection when we can no longer queue packets, this prevents silent data loss, and both peers are notified. Patch 2 increases the total budget to `buf_alloc * 2` for payload plus skb overhead similar to how SO_RCVBUF is doubled to reserve space for sk_buff metadata. This preserves the full buf_alloc for payload under normal operation, while still bounding the skb queue growth. In the future, we plan to improve how we handle the merging of packets to minimize overhead and avoid closing connections. v3: https://lore.kernel.org/netdev/20260513105417.56761-1-sgarzare@redhat.com/ v2: https://lore.kernel.org/netdev/20260512080737.36787-1-sgarzare@redhat.com/ v1: https://lore.kernel.org/netdev/20260508092330.69690-1-sgarzare@redhat.com/ ==================== Link: https://patch.msgid.link/20260518090656.134588-1-sgarzare@redhat.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--net/vmw_vsock/virtio_transport_common.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 1e3409d28164..df3b418e0392 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -419,7 +419,14 @@ static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
{
u64 skb_overhead = (skb_queue_len(&vvs->rx_queue) + 1) * SKB_TRUESIZE(0);
- if (skb_overhead + vvs->buf_used + len > vvs->buf_alloc)
+ /* Allow at most buf_alloc * 2 total budget (payload + overhead),
+ * similar to how SO_RCVBUF is doubled to reserve space for sk_buff
+ * metadata. Check payload against buf_alloc to be sure the other
+ * peer is respecting the credit, and sk_buff overhead to bound
+ * queue growth.
+ */
+ if ((u64)vvs->buf_used + len > vvs->buf_alloc ||
+ skb_overhead > vvs->buf_alloc)
return false;
vvs->rx_bytes += len;
@@ -1335,7 +1342,7 @@ destroy:
return err;
}
-static void
+static bool
virtio_transport_recv_enqueue(struct vsock_sock *vsk,
struct sk_buff *skb)
{
@@ -1350,10 +1357,8 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,
spin_lock_bh(&vvs->rx_lock);
can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
- if (!can_enqueue) {
- free_pkt = true;
+ if (!can_enqueue)
goto out;
- }
if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)
vvs->msg_count++;
@@ -1393,6 +1398,8 @@ out:
spin_unlock_bh(&vvs->rx_lock);
if (free_pkt)
kfree_skb(skb);
+
+ return can_enqueue;
}
static int
@@ -1405,7 +1412,17 @@ virtio_transport_recv_connected(struct sock *sk,
switch (le16_to_cpu(hdr->op)) {
case VIRTIO_VSOCK_OP_RW:
- virtio_transport_recv_enqueue(vsk, skb);
+ if (!virtio_transport_recv_enqueue(vsk, skb)) {
+ /* There is no more space to queue the packet, so let's
+ * close the connection; otherwise, we'll lose data.
+ */
+ (void)virtio_transport_reset(vsk, skb);
+ virtio_transport_do_close(vsk, true);
+ sk->sk_err = ENOBUFS;
+ sk_error_report(sk);
+ vsock_remove_sock(vsk);
+ break;
+ }
vsock_data_ready(sk);
return err;
case VIRTIO_VSOCK_OP_CREDIT_REQUEST: