linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/9] vsock/virtio: SKB allocation improvements
@ 2025-07-14 15:20 Will Deacon
  2025-07-14 15:20 ` [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
                   ` (9 more replies)
  0 siblings, 10 replies; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

Hi folks,

Here is version three of the patches I previously posted here:

  v1: https://lore.kernel.org/r/20250625131543.5155-1-will@kernel.org
  v2: https://lore.kernel.org/r/20250701164507.14883-1-will@kernel.org

Changes since v2 include:

  * Pass payload length as a parameter to virtio_vsock_skb_put()

  * Reinstate VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE based on a 4KiB total
    allocation size

  * Split movement of bounds check into a separate patch

Thanks again to Stefano for all the review feedback so far.

Cheers,

Will

Cc: Keir Fraser <keirf@google.com>
Cc: Steven Moreland <smoreland@google.com>
Cc: Frederick Mayle <fmayle@google.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Stefano Garzarella <sgarzare@redhat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: "Eugenio Pérez" <eperezma@redhat.com>
Cc: linux-kernel@vger.kernel.org 
Cc: netdev@vger.kernel.org 
Cc: virtualization@lists.linux.dev

--->8

Will Deacon (9):
  vhost/vsock: Avoid allocating arbitrarily-sized SKBs
  vsock/virtio: Validate length in packet header before skb_put()
  vsock/virtio: Move length check to callers of
    virtio_vsock_skb_rx_put()
  vsock/virtio: Resize receive buffers so that each SKB fits in a 4K
    page
  vsock/virtio: Rename virtio_vsock_alloc_skb()
  vsock/virtio: Move SKB allocation lower-bound check to callers
  vhost/vsock: Allocate nonlinear SKBs for handling large receive
    buffers
  vsock/virtio: Rename virtio_vsock_skb_rx_put()
  vsock/virtio: Allocate nonlinear SKBs for handling large transmit
    buffers

 drivers/vhost/vsock.c                   | 15 ++++----
 include/linux/virtio_vsock.h            | 46 +++++++++++++++++++------
 net/vmw_vsock/virtio_transport.c        | 20 ++++++++---
 net/vmw_vsock/virtio_transport_common.c |  3 +-
 4 files changed, 60 insertions(+), 24 deletions(-)

-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
@ 2025-07-14 15:20 ` Will Deacon
  2025-07-15  9:47   ` Stefano Garzarella
  2025-07-14 15:20 ` [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put() Will Deacon
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization, stable

vhost_vsock_alloc_skb() returns NULL for packets advertising a length
larger than VIRTIO_VSOCK_MAX_PKT_BUF_SIZE in the packet header. However,
this is only checked once the SKB has been allocated and, if the length
in the packet header is zero, the SKB may not be freed immediately.

Hoist the size check before the SKB allocation so that an iovec larger
than VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + the header size is rejected
outright. The subsequent check on the length field in the header can
then simply check that the allocated SKB is indeed large enough to hold
the packet.

Cc: <stable@vger.kernel.org>
Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 802153e23073..66a0f060770e 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -344,6 +344,9 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 
 	len = iov_length(vq->iov, out);
 
+	if (len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
+		return NULL;
+
 	/* len contains both payload and hdr */
 	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
 	if (!skb)
@@ -367,8 +370,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 		return skb;
 
 	/* The pkt is too big or the length in the header is invalid */
-	if (payload_len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE ||
-	    payload_len + sizeof(*hdr) > len) {
+	if (payload_len + sizeof(*hdr) > len) {
 		kfree_skb(skb);
 		return NULL;
 	}
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put()
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
  2025-07-14 15:20 ` [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
@ 2025-07-14 15:20 ` Will Deacon
  2025-07-15  9:53   ` Stefano Garzarella
  2025-07-14 15:20 ` [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put() Will Deacon
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization, stable

When receiving a vsock packet in the guest, only the virtqueue buffer
size is validated prior to virtio_vsock_skb_rx_put(). Unfortunately,
virtio_vsock_skb_rx_put() uses the length from the packet header as the
length argument to skb_put(), potentially resulting in SKB overflow if
the host has gone wonky.

Validate the length as advertised by the packet header before calling
virtio_vsock_skb_rx_put().

Cc: <stable@vger.kernel.org>
Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
Signed-off-by: Will Deacon <will@kernel.org>
---
 net/vmw_vsock/virtio_transport.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index f0e48e6911fc..bd2c6aaa1a93 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -624,8 +624,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
 	do {
 		virtqueue_disable_cb(vq);
 		for (;;) {
+			unsigned int len, payload_len;
+			struct virtio_vsock_hdr *hdr;
 			struct sk_buff *skb;
-			unsigned int len;
 
 			if (!virtio_transport_more_replies(vsock)) {
 				/* Stop rx until the device processes already
@@ -642,12 +643,19 @@ static void virtio_transport_rx_work(struct work_struct *work)
 			vsock->rx_buf_nr--;
 
 			/* Drop short/long packets */
-			if (unlikely(len < sizeof(struct virtio_vsock_hdr) ||
+			if (unlikely(len < sizeof(*hdr) ||
 				     len > virtio_vsock_skb_len(skb))) {
 				kfree_skb(skb);
 				continue;
 			}
 
+			hdr = virtio_vsock_hdr(skb);
+			payload_len = le32_to_cpu(hdr->len);
+			if (payload_len > len - sizeof(*hdr)) {
+				kfree_skb(skb);
+				continue;
+			}
+
 			virtio_vsock_skb_rx_put(skb);
 			virtio_transport_deliver_tap_pkt(skb);
 			virtio_transport_recv_pkt(&virtio_transport, skb);
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put()
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
  2025-07-14 15:20 ` [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
  2025-07-14 15:20 ` [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put() Will Deacon
@ 2025-07-14 15:20 ` Will Deacon
  2025-07-15  9:55   ` Stefano Garzarella
  2025-07-14 15:20 ` [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page Will Deacon
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

virtio_vsock_skb_rx_put() only calls skb_put() if the length in the
packet header is not zero even though skb_put() handles this case
gracefully.

Remove the functionally redundant check from virtio_vsock_skb_rx_put()
and, on the assumption that this is a worthwhile optimisation for
handling credit messages, augment the existing length checks in
virtio_transport_rx_work() to elide the call for zero-length payloads.
Since the callers all have the length, extend virtio_vsock_skb_rx_put()
to take it as an additional parameter rather than fish it back out of
the packet header.

Note that the vhost code already has similar logic in
vhost_vsock_alloc_skb().

Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c            | 2 +-
 include/linux/virtio_vsock.h     | 9 ++-------
 net/vmw_vsock/virtio_transport.c | 4 +++-
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 66a0f060770e..4c4a642945eb 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -375,7 +375,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 		return NULL;
 	}
 
-	virtio_vsock_skb_rx_put(skb);
+	virtio_vsock_skb_rx_put(skb, payload_len);
 
 	nbytes = copy_from_iter(skb->data, payload_len, &iov_iter);
 	if (nbytes != payload_len) {
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 36fb3edfa403..97465f378ade 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -47,14 +47,9 @@ static inline void virtio_vsock_skb_clear_tap_delivered(struct sk_buff *skb)
 	VIRTIO_VSOCK_SKB_CB(skb)->tap_delivered = false;
 }
 
-static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb)
+static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
 {
-	u32 len;
-
-	len = le32_to_cpu(virtio_vsock_hdr(skb)->len);
-
-	if (len > 0)
-		skb_put(skb, len);
+	skb_put(skb, len);
 }
 
 static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index bd2c6aaa1a93..1af7723669cb 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -656,7 +656,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
 				continue;
 			}
 
-			virtio_vsock_skb_rx_put(skb);
+			if (payload_len)
+				virtio_vsock_skb_rx_put(skb, payload_len);
+
 			virtio_transport_deliver_tap_pkt(skb);
 			virtio_transport_recv_pkt(&virtio_transport, skb);
 		}
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (2 preceding siblings ...)
  2025-07-14 15:20 ` [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put() Will Deacon
@ 2025-07-14 15:20 ` Will Deacon
  2025-07-15  9:56   ` Stefano Garzarella
  2025-07-14 15:20 ` [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb() Will Deacon
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

When allocating receive buffers for the vsock virtio RX virtqueue, an
SKB is allocated with a 4140 data payload (the 44-byte packet header +
VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE). Even when factoring in the SKB
overhead, the resulting 8KiB allocation thanks to the rounding in
kmalloc_reserve() is wasteful (~3700 unusable bytes) and results in a
higher-order page allocation on systems with 4KiB pages just for the
sake of a few hundred bytes of packet data.

Limit the vsock virtio RX buffers to 4KiB per SKB, resulting in much
better memory utilisation and removing the need to allocate higher-order
pages entirely.

Signed-off-by: Will Deacon <will@kernel.org>
---
 include/linux/virtio_vsock.h     | 7 ++++++-
 net/vmw_vsock/virtio_transport.c | 2 +-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 97465f378ade..879f1dfa7d3a 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -106,7 +106,12 @@ static inline size_t virtio_vsock_skb_len(struct sk_buff *skb)
 	return (size_t)(skb_end_pointer(skb) - skb->head);
 }
 
-#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE	(1024 * 4)
+/* Dimension the RX SKB so that the entire thing fits exactly into
+ * a single 4KiB page. This avoids wasting memory due to alloc_skb()
+ * rounding up to the next page order and also means that we
+ * don't leave higher-order pages sitting around in the RX queue.
+ */
+#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE	SKB_WITH_OVERHEAD(1024 * 4)
 #define VIRTIO_VSOCK_MAX_BUF_SIZE		0xFFFFFFFFUL
 #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE		(1024 * 64)
 
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 1af7723669cb..5416214ae666 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -307,7 +307,7 @@ virtio_transport_cancel_pkt(struct vsock_sock *vsk)
 
 static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
 {
-	int total_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM;
+	int total_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE;
 	struct scatterlist pkt, *p;
 	struct virtqueue *vq;
 	struct sk_buff *skb;
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb()
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (3 preceding siblings ...)
  2025-07-14 15:20 ` [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page Will Deacon
@ 2025-07-14 15:20 ` Will Deacon
  2025-07-15  9:56   ` Stefano Garzarella
  2025-07-14 15:21 ` [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers Will Deacon
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

In preparation for nonlinear allocations for large SKBs, rename
virtio_vsock_alloc_skb() to virtio_vsock_alloc_linear_skb() to indicate
that it returns linear SKBs unconditionally and switch all callers over
to this new interface for now.

No functional change.

Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c                   | 2 +-
 include/linux/virtio_vsock.h            | 3 ++-
 net/vmw_vsock/virtio_transport.c        | 2 +-
 net/vmw_vsock/virtio_transport_common.c | 2 +-
 4 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 4c4a642945eb..1ad96613680e 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -348,7 +348,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 		return NULL;
 
 	/* len contains both payload and hdr */
-	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
+	skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
 	if (!skb)
 		return NULL;
 
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 879f1dfa7d3a..4504ea29ff82 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -52,7 +52,8 @@ static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
 	skb_put(skb, len);
 }
 
-static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
+static inline struct sk_buff *
+virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
 {
 	struct sk_buff *skb;
 
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 5416214ae666..c983fd62e37a 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -316,7 +316,7 @@ static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
 	vq = vsock->vqs[VSOCK_VQ_RX];
 
 	do {
-		skb = virtio_vsock_alloc_skb(total_len, GFP_KERNEL);
+		skb = virtio_vsock_alloc_linear_skb(total_len, GFP_KERNEL);
 		if (!skb)
 			break;
 
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 1b5d9896edae..c9eb7f7ac00d 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -261,7 +261,7 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *
 	if (!zcopy)
 		skb_len += payload_len;
 
-	skb = virtio_vsock_alloc_skb(skb_len, GFP_KERNEL);
+	skb = virtio_vsock_alloc_linear_skb(skb_len, GFP_KERNEL);
 	if (!skb)
 		return NULL;
 
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (4 preceding siblings ...)
  2025-07-14 15:20 ` [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb() Will Deacon
@ 2025-07-14 15:21 ` Will Deacon
  2025-07-15  9:57   ` Stefano Garzarella
  2025-07-14 15:21 ` [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers Will Deacon
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

virtio_vsock_alloc_linear_skb() checks that the requested size is at
least big enough for the packet header (VIRTIO_VSOCK_SKB_HEADROOM).

Of the three callers of virtio_vsock_alloc_linear_skb(), only
vhost_vsock_alloc_skb() can potentially pass a packet smaller than the
header size and, as it already has a check against the maximum packet
size, extend its bounds checking to consider the minimum packet size
and remove the check from virtio_vsock_alloc_linear_skb().

Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c        | 3 ++-
 include/linux/virtio_vsock.h | 3 ---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 1ad96613680e..24b7547b05a6 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -344,7 +344,8 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 
 	len = iov_length(vq->iov, out);
 
-	if (len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
+	if (len < VIRTIO_VSOCK_SKB_HEADROOM ||
+	    len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
 		return NULL;
 
 	/* len contains both payload and hdr */
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 4504ea29ff82..36dd0cd55368 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -57,9 +57,6 @@ virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
 {
 	struct sk_buff *skb;
 
-	if (size < VIRTIO_VSOCK_SKB_HEADROOM)
-		return NULL;
-
 	skb = alloc_skb(size, mask);
 	if (!skb)
 		return NULL;
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (5 preceding siblings ...)
  2025-07-14 15:21 ` [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers Will Deacon
@ 2025-07-14 15:21 ` Will Deacon
  2025-07-15 10:00   ` Stefano Garzarella
  2025-07-14 15:21 ` [PATCH v3 8/9] vsock/virtio: Rename virtio_vsock_skb_rx_put() Will Deacon
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

When receiving a packet from a guest, vhost_vsock_handle_tx_kick()
calls vhost_vsock_alloc_linear_skb() to allocate and fill an SKB with
the receive data. Unfortunately, these are always linear allocations and
can therefore result in significant pressure on kmalloc() considering
that the maximum packet size (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE +
VIRTIO_VSOCK_SKB_HEADROOM) is a little over 64KiB, resulting in a 128KiB
allocation for each packet.

Rework the vsock SKB allocation so that, for sizes with page order
greater than PAGE_ALLOC_COSTLY_ORDER, a nonlinear SKB is allocated
instead with the packet header in the SKB and the receive data in the
fragments. Finally, add a debug warning if virtio_vsock_skb_rx_put() is
ever called on an SKB with a non-zero length, as this would be
destructive for the nonlinear case.

Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c        |  8 +++-----
 include/linux/virtio_vsock.h | 40 +++++++++++++++++++++++++++++-------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 24b7547b05a6..0679a706ebc0 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -349,7 +349,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 		return NULL;
 
 	/* len contains both payload and hdr */
-	skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
+	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
 	if (!skb)
 		return NULL;
 
@@ -378,10 +378,8 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 
 	virtio_vsock_skb_rx_put(skb, payload_len);
 
-	nbytes = copy_from_iter(skb->data, payload_len, &iov_iter);
-	if (nbytes != payload_len) {
-		vq_err(vq, "Expected %zu byte payload, got %zu bytes\n",
-		       payload_len, nbytes);
+	if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {
+		vq_err(vq, "Failed to copy %zu byte payload\n", payload_len);
 		kfree_skb(skb);
 		return NULL;
 	}
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 36dd0cd55368..fa5934ea9c81 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -49,20 +49,46 @@ static inline void virtio_vsock_skb_clear_tap_delivered(struct sk_buff *skb)
 
 static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
 {
-	skb_put(skb, len);
+	DEBUG_NET_WARN_ON_ONCE(skb->len);
+
+	if (skb_is_nonlinear(skb))
+		skb->len = len;
+	else
+		skb_put(skb, len);
+}
+
+static inline struct sk_buff *
+__virtio_vsock_alloc_skb_with_frags(unsigned int header_len,
+				    unsigned int data_len,
+				    gfp_t mask)
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = alloc_skb_with_frags(header_len, data_len,
+				   PAGE_ALLOC_COSTLY_ORDER, &err, mask);
+	if (!skb)
+		return NULL;
+
+	skb_reserve(skb, VIRTIO_VSOCK_SKB_HEADROOM);
+	skb->data_len = data_len;
+	return skb;
 }
 
 static inline struct sk_buff *
 virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
 {
-	struct sk_buff *skb;
+	return __virtio_vsock_alloc_skb_with_frags(size, 0, mask);
+}
 
-	skb = alloc_skb(size, mask);
-	if (!skb)
-		return NULL;
+static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
+{
+	if (size <= SKB_WITH_OVERHEAD(PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+		return virtio_vsock_alloc_linear_skb(size, mask);
 
-	skb_reserve(skb, VIRTIO_VSOCK_SKB_HEADROOM);
-	return skb;
+	size -= VIRTIO_VSOCK_SKB_HEADROOM;
+	return __virtio_vsock_alloc_skb_with_frags(VIRTIO_VSOCK_SKB_HEADROOM,
+						   size, mask);
 }
 
 static inline void
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 8/9] vsock/virtio: Rename virtio_vsock_skb_rx_put()
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (6 preceding siblings ...)
  2025-07-14 15:21 ` [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers Will Deacon
@ 2025-07-14 15:21 ` Will Deacon
  2025-07-14 15:21 ` [PATCH v3 9/9] vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers Will Deacon
  2025-07-15 10:01 ` [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Stefano Garzarella
  9 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

In preparation for using virtio_vsock_skb_rx_put() when populating SKBs
on the vsock TX path, rename virtio_vsock_skb_rx_put() to
virtio_vsock_skb_put().

No functional change.

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Will Deacon <will@kernel.org>
---
 drivers/vhost/vsock.c            | 2 +-
 include/linux/virtio_vsock.h     | 2 +-
 net/vmw_vsock/virtio_transport.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 0679a706ebc0..ae01457ea2cd 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -376,7 +376,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 		return NULL;
 	}
 
-	virtio_vsock_skb_rx_put(skb, payload_len);
+	virtio_vsock_skb_put(skb, payload_len);
 
 	if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {
 		vq_err(vq, "Failed to copy %zu byte payload\n", payload_len);
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index fa5934ea9c81..0c67543a45c8 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -47,7 +47,7 @@ static inline void virtio_vsock_skb_clear_tap_delivered(struct sk_buff *skb)
 	VIRTIO_VSOCK_SKB_CB(skb)->tap_delivered = false;
 }
 
-static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
+static inline void virtio_vsock_skb_put(struct sk_buff *skb, u32 len)
 {
 	DEBUG_NET_WARN_ON_ONCE(skb->len);
 
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index c983fd62e37a..f65ad8706bbd 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -657,7 +657,7 @@ static void virtio_transport_rx_work(struct work_struct *work)
 			}
 
 			if (payload_len)
-				virtio_vsock_skb_rx_put(skb, payload_len);
+				virtio_vsock_skb_put(skb, payload_len);
 
 			virtio_transport_deliver_tap_pkt(skb);
 			virtio_transport_recv_pkt(&virtio_transport, skb);
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 9/9] vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (7 preceding siblings ...)
  2025-07-14 15:21 ` [PATCH v3 8/9] vsock/virtio: Rename virtio_vsock_skb_rx_put() Will Deacon
@ 2025-07-14 15:21 ` Will Deacon
  2025-07-15 10:01 ` [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Stefano Garzarella
  9 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2025-07-14 15:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Will Deacon, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Stefano Garzarella, Michael S. Tsirkin,
	Jason Wang, Eugenio Pérez, netdev, virtualization

When transmitting a vsock packet, virtio_transport_send_pkt_info() calls
virtio_transport_alloc_linear_skb() to allocate and fill SKBs with the
transmit data. Unfortunately, these are always linear allocations and
can therefore result in significant pressure on kmalloc() considering
that the maximum packet size (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE +
VIRTIO_VSOCK_SKB_HEADROOM) is a little over 64KiB, resulting in a 128KiB
allocation for each packet.

Rework the vsock SKB allocation so that, for sizes with page order
greater than PAGE_ALLOC_COSTLY_ORDER, a nonlinear SKB is allocated
instead with the packet header in the SKB and the transmit data in the
fragments. No that this affects both the vhost and virtio transports.

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Will Deacon <will@kernel.org>
---
 net/vmw_vsock/virtio_transport_common.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index c9eb7f7ac00d..fe92e5fa95b4 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -109,7 +109,8 @@ static int virtio_transport_fill_skb(struct sk_buff *skb,
 		return __zerocopy_sg_from_iter(info->msg, NULL, skb,
 					       &info->msg->msg_iter, len, NULL);
 
-	return memcpy_from_msg(skb_put(skb, len), info->msg, len);
+	virtio_vsock_skb_put(skb, len);
+	return skb_copy_datagram_from_iter(skb, 0, &info->msg->msg_iter, len);
 }
 
 static void virtio_transport_init_hdr(struct sk_buff *skb,
@@ -261,7 +262,7 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *
 	if (!zcopy)
 		skb_len += payload_len;
 
-	skb = virtio_vsock_alloc_linear_skb(skb_len, GFP_KERNEL);
+	skb = virtio_vsock_alloc_skb(skb_len, GFP_KERNEL);
 	if (!skb)
 		return NULL;
 
-- 
2.50.0.727.gbf7dc18ff4-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs
  2025-07-14 15:20 ` [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
@ 2025-07-15  9:47   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:47 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization, stable

On Mon, Jul 14, 2025 at 04:20:55PM +0100, Will Deacon wrote:
>vhost_vsock_alloc_skb() returns NULL for packets advertising a length
>larger than VIRTIO_VSOCK_MAX_PKT_BUF_SIZE in the packet header. However,
>this is only checked once the SKB has been allocated and, if the length
>in the packet header is zero, the SKB may not be freed immediately.
>
>Hoist the size check before the SKB allocation so that an iovec larger
>than VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + the header size is rejected
>outright. The subsequent check on the length field in the header can
>then simply check that the allocated SKB is indeed large enough to hold
>the packet.
>
>Cc: <stable@vger.kernel.org>
>Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> drivers/vhost/vsock.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>index 802153e23073..66a0f060770e 100644
>--- a/drivers/vhost/vsock.c
>+++ b/drivers/vhost/vsock.c
>@@ -344,6 +344,9 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
>
> 	len = iov_length(vq->iov, out);
>
>+	if (len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
>+		return NULL;
>+
> 	/* len contains both payload and hdr */
> 	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
> 	if (!skb)
>@@ -367,8 +370,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
> 		return skb;
>
> 	/* The pkt is too big or the length in the header is invalid */
>-	if (payload_len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE ||
>-	    payload_len + sizeof(*hdr) > len) {
>+	if (payload_len + sizeof(*hdr) > len) {
> 		kfree_skb(skb);
> 		return NULL;
> 	}
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put()
  2025-07-14 15:20 ` [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put() Will Deacon
@ 2025-07-15  9:53   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:53 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization, stable

On Mon, Jul 14, 2025 at 04:20:56PM +0100, Will Deacon wrote:
>When receiving a vsock packet in the guest, only the virtqueue buffer
>size is validated prior to virtio_vsock_skb_rx_put(). Unfortunately,
>virtio_vsock_skb_rx_put() uses the length from the packet header as the
>length argument to skb_put(), potentially resulting in SKB overflow if
>the host has gone wonky.
>
>Validate the length as advertised by the packet header before calling
>virtio_vsock_skb_rx_put().
>
>Cc: <stable@vger.kernel.org>
>Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> net/vmw_vsock/virtio_transport.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
>diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
>index f0e48e6911fc..bd2c6aaa1a93 100644
>--- a/net/vmw_vsock/virtio_transport.c
>+++ b/net/vmw_vsock/virtio_transport.c
>@@ -624,8 +624,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
> 	do {
> 		virtqueue_disable_cb(vq);
> 		for (;;) {
>+			unsigned int len, payload_len;
>+			struct virtio_vsock_hdr *hdr;
> 			struct sk_buff *skb;
>-			unsigned int len;
>
> 			if (!virtio_transport_more_replies(vsock)) {
> 				/* Stop rx until the device processes already
>@@ -642,12 +643,19 @@ static void virtio_transport_rx_work(struct work_struct *work)
> 			vsock->rx_buf_nr--;
>
> 			/* Drop short/long packets */
>-			if (unlikely(len < sizeof(struct virtio_vsock_hdr) ||
>+			if (unlikely(len < sizeof(*hdr) ||

pre-existing: in some part we use sizeof(*hdr) in other 
VIRTIO_VSOCK_SKB_HEADROOM, I think we should try to uniform that, but of 
course not for this series!

> 				     len > virtio_vsock_skb_len(skb))) {
> 				kfree_skb(skb);
> 				continue;
> 			}
>
>+			hdr = virtio_vsock_hdr(skb);
>+			payload_len = le32_to_cpu(hdr->len);
>+			if (payload_len > len - sizeof(*hdr)) {

Since this is an hot path, should we use `unlikely`, like in the 
previous check, to instruct the branch predictor?

The rest LGTM!

Thanks,
Stefano

>+				kfree_skb(skb);
>+				continue;
>+			}
>+
> 			virtio_vsock_skb_rx_put(skb);
> 			virtio_transport_deliver_tap_pkt(skb);
> 			virtio_transport_recv_pkt(&virtio_transport, skb);
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put()
  2025-07-14 15:20 ` [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put() Will Deacon
@ 2025-07-15  9:55   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:55 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:20:57PM +0100, Will Deacon wrote:
>virtio_vsock_skb_rx_put() only calls skb_put() if the length in the
>packet header is not zero even though skb_put() handles this case
>gracefully.
>
>Remove the functionally redundant check from virtio_vsock_skb_rx_put()
>and, on the assumption that this is a worthwhile optimisation for
>handling credit messages, augment the existing length checks in
>virtio_transport_rx_work() to elide the call for zero-length payloads.
>Since the callers all have the length, extend virtio_vsock_skb_rx_put()
>to take it as an additional parameter rather than fish it back out of
>the packet header.
>
>Note that the vhost code already has similar logic in
>vhost_vsock_alloc_skb().
>
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> drivers/vhost/vsock.c            | 2 +-
> include/linux/virtio_vsock.h     | 9 ++-------
> net/vmw_vsock/virtio_transport.c | 4 +++-
> 3 files changed, 6 insertions(+), 9 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>index 66a0f060770e..4c4a642945eb 100644
>--- a/drivers/vhost/vsock.c
>+++ b/drivers/vhost/vsock.c
>@@ -375,7 +375,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
> 		return NULL;
> 	}
>
>-	virtio_vsock_skb_rx_put(skb);
>+	virtio_vsock_skb_rx_put(skb, payload_len);
>
> 	nbytes = copy_from_iter(skb->data, payload_len, &iov_iter);
> 	if (nbytes != payload_len) {
>diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
>index 36fb3edfa403..97465f378ade 100644
>--- a/include/linux/virtio_vsock.h
>+++ b/include/linux/virtio_vsock.h
>@@ -47,14 +47,9 @@ static inline void virtio_vsock_skb_clear_tap_delivered(struct sk_buff *skb)
> 	VIRTIO_VSOCK_SKB_CB(skb)->tap_delivered = false;
> }
>
>-static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb)
>+static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
> {
>-	u32 len;
>-
>-	len = le32_to_cpu(virtio_vsock_hdr(skb)->len);
>-
>-	if (len > 0)
>-		skb_put(skb, len);
>+	skb_put(skb, len);
> }
>
> static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
>diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
>index bd2c6aaa1a93..1af7723669cb 100644
>--- a/net/vmw_vsock/virtio_transport.c
>+++ b/net/vmw_vsock/virtio_transport.c
>@@ -656,7 +656,9 @@ static void virtio_transport_rx_work(struct work_struct *work)
> 				continue;
> 			}
>
>-			virtio_vsock_skb_rx_put(skb);
>+			if (payload_len)
>+				virtio_vsock_skb_rx_put(skb, payload_len);
>+
> 			virtio_transport_deliver_tap_pkt(skb);
> 			virtio_transport_recv_pkt(&virtio_transport, skb);
> 		}
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page
  2025-07-14 15:20 ` [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page Will Deacon
@ 2025-07-15  9:56   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:56 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:20:58PM +0100, Will Deacon wrote:
>When allocating receive buffers for the vsock virtio RX virtqueue, an
>SKB is allocated with a 4140 data payload (the 44-byte packet header +
>VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE). Even when factoring in the SKB
>overhead, the resulting 8KiB allocation thanks to the rounding in
>kmalloc_reserve() is wasteful (~3700 unusable bytes) and results in a
>higher-order page allocation on systems with 4KiB pages just for the
>sake of a few hundred bytes of packet data.
>
>Limit the vsock virtio RX buffers to 4KiB per SKB, resulting in much
>better memory utilisation and removing the need to allocate higher-order
>pages entirely.
>
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> include/linux/virtio_vsock.h     | 7 ++++++-
> net/vmw_vsock/virtio_transport.c | 2 +-
> 2 files changed, 7 insertions(+), 2 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
>index 97465f378ade..879f1dfa7d3a 100644
>--- a/include/linux/virtio_vsock.h
>+++ b/include/linux/virtio_vsock.h
>@@ -106,7 +106,12 @@ static inline size_t virtio_vsock_skb_len(struct sk_buff *skb)
> 	return (size_t)(skb_end_pointer(skb) - skb->head);
> }
>
>-#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE	(1024 * 4)
>+/* Dimension the RX SKB so that the entire thing fits exactly into
>+ * a single 4KiB page. This avoids wasting memory due to alloc_skb()
>+ * rounding up to the next page order and also means that we
>+ * don't leave higher-order pages sitting around in the RX queue.
>+ */
>+#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE	SKB_WITH_OVERHEAD(1024 * 4)
> #define VIRTIO_VSOCK_MAX_BUF_SIZE		0xFFFFFFFFUL
> #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE		(1024 * 64)
>
>diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
>index 1af7723669cb..5416214ae666 100644
>--- a/net/vmw_vsock/virtio_transport.c
>+++ b/net/vmw_vsock/virtio_transport.c
>@@ -307,7 +307,7 @@ virtio_transport_cancel_pkt(struct vsock_sock *vsk)
>
> static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
> {
>-	int total_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM;
>+	int total_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE;
> 	struct scatterlist pkt, *p;
> 	struct virtqueue *vq;
> 	struct sk_buff *skb;
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb()
  2025-07-14 15:20 ` [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb() Will Deacon
@ 2025-07-15  9:56   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:56 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:20:59PM +0100, Will Deacon wrote:
>In preparation for nonlinear allocations for large SKBs, rename
>virtio_vsock_alloc_skb() to virtio_vsock_alloc_linear_skb() to indicate
>that it returns linear SKBs unconditionally and switch all callers over
>to this new interface for now.
>
>No functional change.
>
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> drivers/vhost/vsock.c                   | 2 +-
> include/linux/virtio_vsock.h            | 3 ++-
> net/vmw_vsock/virtio_transport.c        | 2 +-
> net/vmw_vsock/virtio_transport_common.c | 2 +-
> 4 files changed, 5 insertions(+), 4 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>index 4c4a642945eb..1ad96613680e 100644
>--- a/drivers/vhost/vsock.c
>+++ b/drivers/vhost/vsock.c
>@@ -348,7 +348,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
> 		return NULL;
>
> 	/* len contains both payload and hdr */
>-	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
>+	skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
> 	if (!skb)
> 		return NULL;
>
>diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
>index 879f1dfa7d3a..4504ea29ff82 100644
>--- a/include/linux/virtio_vsock.h
>+++ b/include/linux/virtio_vsock.h
>@@ -52,7 +52,8 @@ static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
> 	skb_put(skb, len);
> }
>
>-static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
>+static inline struct sk_buff *
>+virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
> {
> 	struct sk_buff *skb;
>
>diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
>index 5416214ae666..c983fd62e37a 100644
>--- a/net/vmw_vsock/virtio_transport.c
>+++ b/net/vmw_vsock/virtio_transport.c
>@@ -316,7 +316,7 @@ static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
> 	vq = vsock->vqs[VSOCK_VQ_RX];
>
> 	do {
>-		skb = virtio_vsock_alloc_skb(total_len, GFP_KERNEL);
>+		skb = virtio_vsock_alloc_linear_skb(total_len, GFP_KERNEL);
> 		if (!skb)
> 			break;
>
>diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>index 1b5d9896edae..c9eb7f7ac00d 100644
>--- a/net/vmw_vsock/virtio_transport_common.c
>+++ b/net/vmw_vsock/virtio_transport_common.c
>@@ -261,7 +261,7 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *
> 	if (!zcopy)
> 		skb_len += payload_len;
>
>-	skb = virtio_vsock_alloc_skb(skb_len, GFP_KERNEL);
>+	skb = virtio_vsock_alloc_linear_skb(skb_len, GFP_KERNEL);
> 	if (!skb)
> 		return NULL;
>
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers
  2025-07-14 15:21 ` [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers Will Deacon
@ 2025-07-15  9:57   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15  9:57 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:21:00PM +0100, Will Deacon wrote:
>virtio_vsock_alloc_linear_skb() checks that the requested size is at
>least big enough for the packet header (VIRTIO_VSOCK_SKB_HEADROOM).
>
>Of the three callers of virtio_vsock_alloc_linear_skb(), only
>vhost_vsock_alloc_skb() can potentially pass a packet smaller than the
>header size and, as it already has a check against the maximum packet
>size, extend its bounds checking to consider the minimum packet size
>and remove the check from virtio_vsock_alloc_linear_skb().
>
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> drivers/vhost/vsock.c        | 3 ++-
> include/linux/virtio_vsock.h | 3 ---
> 2 files changed, 2 insertions(+), 4 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>index 1ad96613680e..24b7547b05a6 100644
>--- a/drivers/vhost/vsock.c
>+++ b/drivers/vhost/vsock.c
>@@ -344,7 +344,8 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
>
> 	len = iov_length(vq->iov, out);
>
>-	if (len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
>+	if (len < VIRTIO_VSOCK_SKB_HEADROOM ||
>+	    len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
> 		return NULL;
>
> 	/* len contains both payload and hdr */
>diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
>index 4504ea29ff82..36dd0cd55368 100644
>--- a/include/linux/virtio_vsock.h
>+++ b/include/linux/virtio_vsock.h
>@@ -57,9 +57,6 @@ virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
> {
> 	struct sk_buff *skb;
>
>-	if (size < VIRTIO_VSOCK_SKB_HEADROOM)
>-		return NULL;
>-
> 	skb = alloc_skb(size, mask);
> 	if (!skb)
> 		return NULL;
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers
  2025-07-14 15:21 ` [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers Will Deacon
@ 2025-07-15 10:00   ` Stefano Garzarella
  0 siblings, 0 replies; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15 10:00 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:21:01PM +0100, Will Deacon wrote:
>When receiving a packet from a guest, vhost_vsock_handle_tx_kick()
>calls vhost_vsock_alloc_linear_skb() to allocate and fill an SKB with
>the receive data. Unfortunately, these are always linear allocations and
>can therefore result in significant pressure on kmalloc() considering
>that the maximum packet size (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE +
>VIRTIO_VSOCK_SKB_HEADROOM) is a little over 64KiB, resulting in a 128KiB
>allocation for each packet.
>
>Rework the vsock SKB allocation so that, for sizes with page order
>greater than PAGE_ALLOC_COSTLY_ORDER, a nonlinear SKB is allocated
>instead with the packet header in the SKB and the receive data in the
>fragments. Finally, add a debug warning if virtio_vsock_skb_rx_put() is
>ever called on an SKB with a non-zero length, as this would be
>destructive for the nonlinear case.
>
>Signed-off-by: Will Deacon <will@kernel.org>
>---
> drivers/vhost/vsock.c        |  8 +++-----
> include/linux/virtio_vsock.h | 40 +++++++++++++++++++++++++++++-------
> 2 files changed, 36 insertions(+), 12 deletions(-)

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

>
>diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
>index 24b7547b05a6..0679a706ebc0 100644
>--- a/drivers/vhost/vsock.c
>+++ b/drivers/vhost/vsock.c
>@@ -349,7 +349,7 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
> 		return NULL;
>
> 	/* len contains both payload and hdr */
>-	skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
>+	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
> 	if (!skb)
> 		return NULL;
>
>@@ -378,10 +378,8 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
>
> 	virtio_vsock_skb_rx_put(skb, payload_len);
>
>-	nbytes = copy_from_iter(skb->data, payload_len, &iov_iter);
>-	if (nbytes != payload_len) {
>-		vq_err(vq, "Expected %zu byte payload, got %zu bytes\n",
>-		       payload_len, nbytes);
>+	if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {
>+		vq_err(vq, "Failed to copy %zu byte payload\n", payload_len);
> 		kfree_skb(skb);
> 		return NULL;
> 	}
>diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
>index 36dd0cd55368..fa5934ea9c81 100644
>--- a/include/linux/virtio_vsock.h
>+++ b/include/linux/virtio_vsock.h
>@@ -49,20 +49,46 @@ static inline void virtio_vsock_skb_clear_tap_delivered(struct sk_buff *skb)
>
> static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
> {
>-	skb_put(skb, len);
>+	DEBUG_NET_WARN_ON_ONCE(skb->len);
>+
>+	if (skb_is_nonlinear(skb))
>+		skb->len = len;
>+	else
>+		skb_put(skb, len);
>+}
>+
>+static inline struct sk_buff *
>+__virtio_vsock_alloc_skb_with_frags(unsigned int header_len,
>+				    unsigned int data_len,
>+				    gfp_t mask)
>+{
>+	struct sk_buff *skb;
>+	int err;
>+
>+	skb = alloc_skb_with_frags(header_len, data_len,
>+				   PAGE_ALLOC_COSTLY_ORDER, &err, mask);
>+	if (!skb)
>+		return NULL;
>+
>+	skb_reserve(skb, VIRTIO_VSOCK_SKB_HEADROOM);
>+	skb->data_len = data_len;
>+	return skb;
> }
>
> static inline struct sk_buff *
> virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
> {
>-	struct sk_buff *skb;
>+	return __virtio_vsock_alloc_skb_with_frags(size, 0, mask);
>+}
>
>-	skb = alloc_skb(size, mask);
>-	if (!skb)
>-		return NULL;
>+static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
>+{
>+	if (size <= SKB_WITH_OVERHEAD(PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
>+		return virtio_vsock_alloc_linear_skb(size, mask);
>
>-	skb_reserve(skb, VIRTIO_VSOCK_SKB_HEADROOM);
>-	return skb;
>+	size -= VIRTIO_VSOCK_SKB_HEADROOM;
>+	return __virtio_vsock_alloc_skb_with_frags(VIRTIO_VSOCK_SKB_HEADROOM,
>+						   size, mask);
> }
>
> static inline void
>-- 
>2.50.0.727.gbf7dc18ff4-goog
>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/9] vsock/virtio: SKB allocation improvements
  2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
                   ` (8 preceding siblings ...)
  2025-07-14 15:21 ` [PATCH v3 9/9] vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers Will Deacon
@ 2025-07-15 10:01 ` Stefano Garzarella
  2025-07-15 15:05   ` Will Deacon
  9 siblings, 1 reply; 19+ messages in thread
From: Stefano Garzarella @ 2025-07-15 10:01 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Mon, Jul 14, 2025 at 04:20:54PM +0100, Will Deacon wrote:
>Hi folks,
>
>Here is version three of the patches I previously posted here:
>
>  v1: https://lore.kernel.org/r/20250625131543.5155-1-will@kernel.org
>  v2: https://lore.kernel.org/r/20250701164507.14883-1-will@kernel.org
>
>Changes since v2 include:
>
>  * Pass payload length as a parameter to virtio_vsock_skb_put()
>
>  * Reinstate VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE based on a 4KiB total
>    allocation size
>
>  * Split movement of bounds check into a separate patch
>
>Thanks again to Stefano for all the review feedback so far.

Thanks for the series!
I left just a small comment on a patch, the rest LGTM!

I run my test suite without any issue!

Thanks,
Stefano


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/9] vsock/virtio: SKB allocation improvements
  2025-07-15 10:01 ` [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Stefano Garzarella
@ 2025-07-15 15:05   ` Will Deacon
  0 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2025-07-15 15:05 UTC (permalink / raw)
  To: Stefano Garzarella
  Cc: linux-kernel, Keir Fraser, Steven Moreland, Frederick Mayle,
	Stefan Hajnoczi, Michael S. Tsirkin, Jason Wang,
	Eugenio Pérez, netdev, virtualization

On Tue, Jul 15, 2025 at 12:01:56PM +0200, Stefano Garzarella wrote:
> On Mon, Jul 14, 2025 at 04:20:54PM +0100, Will Deacon wrote:
> > Hi folks,
> > 
> > Here is version three of the patches I previously posted here:
> > 
> >  v1: https://lore.kernel.org/r/20250625131543.5155-1-will@kernel.org
> >  v2: https://lore.kernel.org/r/20250701164507.14883-1-will@kernel.org
> > 
> > Changes since v2 include:
> > 
> >  * Pass payload length as a parameter to virtio_vsock_skb_put()
> > 
> >  * Reinstate VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE based on a 4KiB total
> >    allocation size
> > 
> >  * Split movement of bounds check into a separate patch
> > 
> > Thanks again to Stefano for all the review feedback so far.
> 
> Thanks for the series!
> I left just a small comment on a patch, the rest LGTM!
> 
> I run my test suite without any issue!

Thank, Stefano. I'll send a v4 later this week with your R-b tags and
an unlikely() in the second patch.

Will

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2025-07-15 15:05 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-14 15:20 [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Will Deacon
2025-07-14 15:20 ` [PATCH v3 1/9] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
2025-07-15  9:47   ` Stefano Garzarella
2025-07-14 15:20 ` [PATCH v3 2/9] vsock/virtio: Validate length in packet header before skb_put() Will Deacon
2025-07-15  9:53   ` Stefano Garzarella
2025-07-14 15:20 ` [PATCH v3 3/9] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put() Will Deacon
2025-07-15  9:55   ` Stefano Garzarella
2025-07-14 15:20 ` [PATCH v3 4/9] vsock/virtio: Resize receive buffers so that each SKB fits in a 4K page Will Deacon
2025-07-15  9:56   ` Stefano Garzarella
2025-07-14 15:20 ` [PATCH v3 5/9] vsock/virtio: Rename virtio_vsock_alloc_skb() Will Deacon
2025-07-15  9:56   ` Stefano Garzarella
2025-07-14 15:21 ` [PATCH v3 6/9] vsock/virtio: Move SKB allocation lower-bound check to callers Will Deacon
2025-07-15  9:57   ` Stefano Garzarella
2025-07-14 15:21 ` [PATCH v3 7/9] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers Will Deacon
2025-07-15 10:00   ` Stefano Garzarella
2025-07-14 15:21 ` [PATCH v3 8/9] vsock/virtio: Rename virtio_vsock_skb_rx_put() Will Deacon
2025-07-14 15:21 ` [PATCH v3 9/9] vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers Will Deacon
2025-07-15 10:01 ` [PATCH v3 0/9] vsock/virtio: SKB allocation improvements Stefano Garzarella
2025-07-15 15:05   ` Will Deacon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).