linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Will Deacon <will@kernel.org>
To: linux-kernel@vger.kernel.org
Cc: "Will Deacon" <will@kernel.org>, "Keir Fraser" <keirf@google.com>,
	"Steven Moreland" <smoreland@google.com>,
	"Frederick Mayle" <fmayle@google.com>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Stefano Garzarella" <sgarzare@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Jason Wang" <jasowang@redhat.com>,
	"Eugenio Pérez" <eperezma@redhat.com>,
	netdev@vger.kernel.org, virtualization@lists.linux.dev
Subject: [PATCH v2 6/8] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers
Date: Tue,  1 Jul 2025 17:45:05 +0100	[thread overview]
Message-ID: <20250701164507.14883-7-will@kernel.org> (raw)
In-Reply-To: <20250701164507.14883-1-will@kernel.org>

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. Move the VIRTIO_VSOCK_SKB_HEADROOM check out of the
allocation function and into the single caller that needs it and 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        | 11 +++++------
 include/linux/virtio_vsock.h | 32 +++++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index b13f6be452ba..f3c2ea1d0ae7 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -344,11 +344,12 @@ 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 */
-	skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
+	skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
 	if (!skb)
 		return NULL;
 
@@ -377,10 +378,8 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
 
 	virtio_vsock_skb_rx_put(skb);
 
-	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 6d4a933c895a..ad69668f6b91 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -51,29 +51,47 @@ static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb)
 {
 	u32 len;
 
+	DEBUG_NET_WARN_ON_ONCE(skb->len);
 	len = le32_to_cpu(virtio_vsock_hdr(skb)->len);
-	skb_put(skb, len);
+
+	if (skb_is_nonlinear(skb))
+		skb->len = len;
+	else
+		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_skb_with_frags(unsigned int header_len,
+				    unsigned int data_len,
+				    gfp_t mask)
 {
 	struct sk_buff *skb;
+	int err;
 
-	if (size < VIRTIO_VSOCK_SKB_HEADROOM)
-		return NULL;
-
-	skb = alloc_skb(size, mask);
+	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)
 {
-	return virtio_vsock_alloc_skb(size, mask);
+	return __virtio_vsock_alloc_skb_with_frags(size, 0, mask);
+}
+
+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);
+
+	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


  parent reply	other threads:[~2025-07-01 16:45 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-01 16:44 [PATCH v2 0/8] vsock/virtio: SKB allocation improvements Will Deacon
2025-07-01 16:45 ` [PATCH v2 1/8] vhost/vsock: Avoid allocating arbitrarily-sized SKBs Will Deacon
2025-07-01 16:45 ` [PATCH v2 2/8] vsock/virtio: Validate length in packet header before skb_put() Will Deacon
2025-07-01 16:45 ` [PATCH v2 3/8] vsock/virtio: Move length check to callers of virtio_vsock_skb_rx_put() Will Deacon
2025-07-02 16:28   ` Stefano Garzarella
2025-07-13 21:26     ` Will Deacon
2025-07-01 16:45 ` [PATCH v2 4/8] vsock/virtio: Resize receive buffers so that each SKB fits in a page Will Deacon
2025-07-01 19:14   ` David Laight
2025-07-02 13:16     ` Stefano Garzarella
2025-07-13 21:26       ` Will Deacon
2025-07-01 16:45 ` [PATCH v2 5/8] vsock/virtio: Add vsock helper for linear SKB allocation Will Deacon
2025-07-02 16:40   ` Stefano Garzarella
2025-07-13 21:26     ` Will Deacon
2025-07-01 16:45 ` Will Deacon [this message]
2025-07-02 16:50   ` [PATCH v2 6/8] vhost/vsock: Allocate nonlinear SKBs for handling large receive buffers Stefano Garzarella
2025-07-13 21:37     ` Will Deacon
2025-07-01 16:45 ` [PATCH v2 7/8] vsock/virtio: Rename virtio_vsock_skb_rx_put() to virtio_vsock_skb_put() Will Deacon
2025-07-01 16:45 ` [PATCH v2 8/8] vsock/virtio: Allocate nonlinear SKBs for handling large transmit buffers Will Deacon
2025-07-02 16:52   ` Stefano Garzarella
2025-07-04  9:50 ` [PATCH v2 0/8] vsock/virtio: SKB allocation improvements Lei Yang
2025-07-13 20:18   ` Will Deacon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250701164507.14883-7-will@kernel.org \
    --to=will@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=fmayle@google.com \
    --cc=jasowang@redhat.com \
    --cc=keirf@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=sgarzare@redhat.com \
    --cc=smoreland@google.com \
    --cc=stefanha@redhat.com \
    --cc=virtualization@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).