Commit ba7438ae authored by Al Viro's avatar Al Viro

vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: kvm@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 98a527aa
...@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref { ...@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {
struct vhost_net_virtqueue { struct vhost_net_virtqueue {
struct vhost_virtqueue vq; struct vhost_virtqueue vq;
/* hdr is used to store the virtio header.
* Since each iovec has >= 1 byte length, we never need more than
* header length entries to store the header. */
struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)];
size_t vhost_hlen; size_t vhost_hlen;
size_t sock_hlen; size_t sock_hlen;
/* vhost zerocopy support fields below: */ /* vhost zerocopy support fields below: */
...@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock) ...@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)
sock_flag(sock->sk, SOCK_ZEROCOPY); sock_flag(sock->sk, SOCK_ZEROCOPY);
} }
/* Pop first len bytes from iovec. Return number of segments used. */
static int move_iovec_hdr(struct iovec *from, struct iovec *to,
size_t len, int iov_count)
{
int seg = 0;
size_t size;
while (len && seg < iov_count) {
size = min(from->iov_len, len);
to->iov_base = from->iov_base;
to->iov_len = size;
from->iov_len -= size;
from->iov_base += size;
len -= size;
++from;
++to;
++seg;
}
return seg;
}
/* Copy iovec entries for len bytes from iovec. */
static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
size_t len, int iovcount)
{
int seg = 0;
size_t size;
while (len && seg < iovcount) {
size = min(from->iov_len, len);
to->iov_base = from->iov_base;
to->iov_len = size;
len -= size;
++from;
++to;
++seg;
}
}
/* In case of DMA done not in order in lower device driver for some reason. /* In case of DMA done not in order in lower device driver for some reason.
* upend_idx is used to track end of used idx, done_idx is used to track head * upend_idx is used to track end of used idx, done_idx is used to track head
* of used idx. Once lower device DMA done contiguously, we will signal KVM * of used idx. Once lower device DMA done contiguously, we will signal KVM
...@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) ...@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net)
.msg_controllen = 0, .msg_controllen = 0,
.msg_flags = MSG_DONTWAIT, .msg_flags = MSG_DONTWAIT,
}; };
struct virtio_net_hdr_mrg_rxbuf hdr = { struct virtio_net_hdr hdr = {
.hdr.flags = 0, .flags = 0,
.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE .gso_type = VIRTIO_NET_HDR_GSO_NONE
}; };
size_t total_len = 0; size_t total_len = 0;
int err, mergeable; int err, mergeable;
...@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net) ...@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)
size_t vhost_hlen, sock_hlen; size_t vhost_hlen, sock_hlen;
size_t vhost_len, sock_len; size_t vhost_len, sock_len;
struct socket *sock; struct socket *sock;
struct iov_iter fixup;
mutex_lock(&vq->mutex); mutex_lock(&vq->mutex);
sock = vq->private_data; sock = vq->private_data;
...@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net) ...@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net)
break; break;
} }
/* We don't need to be notified again. */ /* We don't need to be notified again. */
if (unlikely((vhost_hlen))) iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
/* Skip header. TODO: support TSO. */ fixup = msg.msg_iter;
move_iovec_hdr(vq->iov, nvq->hdr, vhost_hlen, in); if (unlikely((vhost_hlen))) {
else /* We will supply the header ourselves
/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: * TODO: support TSO.
* needed because recvmsg can modify msg_iov. */ */
copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in); iov_iter_advance(&msg.msg_iter, vhost_hlen);
iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len); } else {
/* It'll come from socket; we'll need to patch
* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
*/
iov_iter_advance(&fixup, sizeof(hdr));
}
err = sock->ops->recvmsg(NULL, sock, &msg, err = sock->ops->recvmsg(NULL, sock, &msg,
sock_len, MSG_DONTWAIT | MSG_TRUNC); sock_len, MSG_DONTWAIT | MSG_TRUNC);
/* Userspace might have consumed the packet meanwhile: /* Userspace might have consumed the packet meanwhile:
...@@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net) ...@@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net)
vhost_discard_vq_desc(vq, headcount); vhost_discard_vq_desc(vq, headcount);
continue; continue;
} }
/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
if (unlikely(vhost_hlen) && if (unlikely(vhost_hlen) &&
memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0, copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
vhost_hlen)) {
vq_err(vq, "Unable to write vnet_hdr at addr %p\n", vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
vq->iov->iov_base); vq->iov->iov_base);
break; break;
} }
/* TODO: Should check and handle checksum. */ /* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF
* TODO: Should check and handle checksum.
*/
if (likely(mergeable) && if (likely(mergeable) &&
memcpy_toiovecend(nvq->hdr, (unsigned char *)&headcount, copy_to_iter(&headcount, 2, &fixup) != 2) {
offsetof(typeof(hdr), num_buffers),
sizeof hdr.num_buffers)) {
vq_err(vq, "Failed num_buffers write"); vq_err(vq, "Failed num_buffers write");
vhost_discard_vq_desc(vq, headcount); vhost_discard_vq_desc(vq, headcount);
break; break;
......
...@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct io ...@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct io
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
int offset, int len); int offset, int len);
int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
int offset, int len);
#endif #endif
...@@ -2,32 +2,6 @@ ...@@ -2,32 +2,6 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/uio.h> #include <linux/uio.h>
/*
* Copy kernel to iovec. Returns -EFAULT on error.
*/
int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
int offset, int len)
{
int copy;
for (; len > 0; ++iov) {
/* Skip over the finished iovecs */
if (unlikely(offset >= iov->iov_len)) {
offset -= iov->iov_len;
continue;
}
copy = min_t(unsigned int, iov->iov_len - offset, len);
if (copy_to_user(iov->iov_base + offset, kdata, copy))
return -EFAULT;
offset = 0;
kdata += copy;
len -= copy;
}
return 0;
}
EXPORT_SYMBOL(memcpy_toiovecend);
/* /*
* Copy iovec to kernel. Returns -EFAULT on error. * Copy iovec to kernel. Returns -EFAULT on error.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment