Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp5982639ybc; Wed, 27 Nov 2019 12:52:20 -0800 (PST) X-Google-Smtp-Source: APXvYqw5pC3FYSWqJIAljsiKd5vPzbVXKY51Q4rVplx6p14Jd8t+Tfz+AFHhJWvECe6dtPT0dmah X-Received: by 2002:a17:906:4098:: with SMTP id u24mr50459349ejj.220.1574887940461; Wed, 27 Nov 2019 12:52:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574887940; cv=none; d=google.com; s=arc-20160816; b=sNChFSTBXBzZlAXg46QyBQeWPSylOw+PkkpvkRA6vEPzX+UQ090gDKg9eB63YeLpbD LI/+E5eZaAa4cIxZvfO4AXz6eLYRYrtALpUsRzC6Z/KTPAOSsVXRF/2uV1r8dQg9oTh6 fIzZ1H1puK2L8vrLM82fZ7UMvfxCiOPATpCVm473qJ4lynFf3m7TLTfiZrQrqRsUZ+eg pnORpHRKf+YCAxKLY7YP+5t73x/ExGsEQ7CsSmm2cevztPoYWzAadWEzgDiFnGzjR2jK qdc6ehNfmIlsoLFoNgD4VilbjuSAIQVVs3HeiHIZPiJ0IWG5LGPmr1klFkdt3PX9QAGt 2Iyg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=48d2d5pLk3WZAI8TjF85g/XrRgZSDep6x0+UPMhI1wk=; b=Vw62eLid8V9od1GRXSx866fJrrkU4KoaFEfjSte8oNQq5Kv3SqxqzY+Npu243YOJfi KPXiDRNCgZMAyEYgJrFxvaI4CrKoTJ1+lDrT7NQNtYypO9iK++sNDkt6AZBdwGsVKg5G 9E/cTwFvuzD9s7QyCLzZMgVeSCJdwA/1Ze8Ngq3dvIIhtn+n7MmeNq5+avOZvTqbf3a3 oWJ3e8dHC2tcQWtmLAr37FOlY6D9GbujmiiEE0pleeswrlqvryN/b0Qu5EnnHQBfC6eI 3Ac0g0FDh3Z0/2us5p9ol4mZL6FKfspTTiumiqfePCNXjy4nctim5yWaLnfL11iWcDNz /gPQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="B8A3/iCX"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l36si11803321edc.272.2019.11.27.12.51.56; Wed, 27 Nov 2019 12:52:20 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="B8A3/iCX"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730046AbfK0Uru (ORCPT + 99 others); Wed, 27 Nov 2019 15:47:50 -0500 Received: from mail.kernel.org ([198.145.29.99]:60938 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730031AbfK0Urt (ORCPT ); Wed, 27 Nov 2019 15:47:49 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C27DE217C3; Wed, 27 Nov 2019 20:47:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1574887668; bh=UgCUPv+FXXkrqQZEGsb62ZUpxRa20bdJWsSt6ZQqkLQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B8A3/iCXMIC/p7sXtzwW/hysbvnwN5buueRELOjbaDQH6JKygXrvibixXFfsinj/J Em24btStRUPBHdpRanOb+dLNlxzFMjs+ARwCkvKAk3NVy+P8DJO2IqcQr5HvhkOub3 LvUI28raW3wZs6sGmM0admS8DZ6vjRu3BZLn06hM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Stefano Garzarella , Stefan Hajnoczi , "Michael S. Tsirkin" , "David S. Miller" Subject: [PATCH 4.14 007/211] vhost/vsock: split packets to send using multiple buffers Date: Wed, 27 Nov 2019 21:29:00 +0100 Message-Id: <20191127203050.278790438@linuxfoundation.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191127203049.431810767@linuxfoundation.org> References: <20191127203049.431810767@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Stefano Garzarella commit 6dbd3e66e7785a2f055bf84d98de9b8fd31ff3f5 upstream. If the packets to sent to the guest are bigger than the buffer available, we can split them, using multiple buffers and fixing the length in the packet header. This is safe since virtio-vsock supports only stream sockets. Signed-off-by: Stefano Garzarella Reviewed-by: Stefan Hajnoczi Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vsock.c | 66 +++++++++++++++++++++++--------- net/vmw_vsock/virtio_transport_common.c | 15 +++++-- 2 files changed, 60 insertions(+), 21 deletions(-) --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -103,7 +103,7 @@ vhost_transport_do_send_pkt(struct vhost struct iov_iter iov_iter; unsigned out, in; size_t nbytes; - size_t len; + size_t iov_len, payload_len; int head; spin_lock_bh(&vsock->send_pkt_list_lock); @@ -148,8 +148,24 @@ vhost_transport_do_send_pkt(struct vhost break; } - len = iov_length(&vq->iov[out], in); - iov_iter_init(&iov_iter, READ, &vq->iov[out], in, len); + iov_len = iov_length(&vq->iov[out], in); + if (iov_len < sizeof(pkt->hdr)) { + virtio_transport_free_pkt(pkt); + vq_err(vq, "Buffer len [%zu] too small\n", iov_len); + break; + } + + iov_iter_init(&iov_iter, READ, &vq->iov[out], in, iov_len); + payload_len = pkt->len - pkt->off; + + /* If the packet is greater than the space available in the + * buffer, we split it using multiple buffers. + */ + if (payload_len > iov_len - sizeof(pkt->hdr)) + payload_len = iov_len - sizeof(pkt->hdr); + + /* Set the correct length in the header */ + pkt->hdr.len = cpu_to_le32(payload_len); nbytes = copy_to_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter); if (nbytes != sizeof(pkt->hdr)) { @@ -158,33 +174,47 @@ vhost_transport_do_send_pkt(struct vhost break; } - nbytes = copy_to_iter(pkt->buf, pkt->len, &iov_iter); - if (nbytes != pkt->len) { + nbytes = copy_to_iter(pkt->buf + pkt->off, payload_len, + &iov_iter); + if (nbytes != payload_len) { virtio_transport_free_pkt(pkt); vq_err(vq, "Faulted on copying pkt buf\n"); break; } - vhost_add_used(vq, head, sizeof(pkt->hdr) + pkt->len); + vhost_add_used(vq, head, sizeof(pkt->hdr) + payload_len); added = true; - if (pkt->reply) { - int val; - - val = atomic_dec_return(&vsock->queued_replies); - - /* Do we have resources to resume tx processing? */ - if (val + 1 == tx_vq->num) - restart_tx = true; - } - /* Deliver to monitoring devices all correctly transmitted * packets. */ virtio_transport_deliver_tap_pkt(pkt); - total_len += pkt->len; - virtio_transport_free_pkt(pkt); + pkt->off += payload_len; + total_len += payload_len; + + /* If we didn't send all the payload we can requeue the packet + * to send it with the next available buffer. + */ + if (pkt->off < pkt->len) { + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + } else { + if (pkt->reply) { + int val; + + val = atomic_dec_return(&vsock->queued_replies); + + /* Do we have resources to resume tx + * processing? + */ + if (val + 1 == tx_vq->num) + restart_tx = true; + } + + virtio_transport_free_pkt(pkt); + } } while(likely(!vhost_exceeds_weight(vq, ++pkts, total_len))); if (added) vhost_signal(&vsock->dev, vq); --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -92,8 +92,17 @@ static struct sk_buff *virtio_transport_ struct virtio_vsock_pkt *pkt = opaque; struct af_vsockmon_hdr *hdr; struct sk_buff *skb; + size_t payload_len; + void *payload_buf; - skb = alloc_skb(sizeof(*hdr) + sizeof(pkt->hdr) + pkt->len, + /* A packet could be split to fit the RX buffer, so we can retrieve + * the payload length from the header and the buffer pointer taking + * care of the offset in the original packet. + */ + payload_len = le32_to_cpu(pkt->hdr.len); + payload_buf = pkt->buf + pkt->off; + + skb = alloc_skb(sizeof(*hdr) + sizeof(pkt->hdr) + payload_len, GFP_ATOMIC); if (!skb) return NULL; @@ -133,8 +142,8 @@ static struct sk_buff *virtio_transport_ skb_put_data(skb, &pkt->hdr, sizeof(pkt->hdr)); - if (pkt->len) { - skb_put_data(skb, pkt->buf, pkt->len); + if (payload_len) { + skb_put_data(skb, payload_buf, payload_len); } return skb;