mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-20 19:43:58 +08:00
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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
98a527aac1
commit
ba7438aed9
@ -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)
|
|||||||
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)
|
|||||||
.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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
|||||||
|
|
||||||
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
|
||||||
|
26
lib/iovec.c
26
lib/iovec.c
@ -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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user