On Wed, Feb 04, 2015 at 06:40:08AM +0000, Al Viro wrote:
> From: Al Viro <v...@zeniv.linux.org.uk>
> 
> Cc: Michael S. Tsirkin <m...@redhat.com>
> Cc: kvm@vger.kernel.org
> Cc: virtualizat...@lists.linux-foundation.org
> Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>

Acked-by: Michael S. Tsirkin <m...@redhat.com>

> ---
>  drivers/vhost/net.c | 82 
> +++++++++++++++--------------------------------------
>  include/linux/uio.h |  3 --
>  lib/iovec.c         | 26 -----------------
>  3 files changed, 23 insertions(+), 88 deletions(-)
> 
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index d86cc9b..e022cc4 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {
>  
>  struct vhost_net_virtqueue {
>       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 sock_hlen;
>       /* vhost zerocopy support fields below: */
> @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)
>               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.
>   * 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
> @@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net)
>               .msg_controllen = 0,
>               .msg_flags = MSG_DONTWAIT,
>       };
> -     struct virtio_net_hdr_mrg_rxbuf hdr = {
> -             .hdr.flags = 0,
> -             .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
> +     struct virtio_net_hdr hdr = {
> +             .flags = 0,
> +             .gso_type = VIRTIO_NET_HDR_GSO_NONE
>       };
>       size_t total_len = 0;
>       int err, mergeable;
> @@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)
>       size_t vhost_hlen, sock_hlen;
>       size_t vhost_len, sock_len;
>       struct socket *sock;
> +     struct iov_iter fixup;
>  
>       mutex_lock(&vq->mutex);
>       sock = vq->private_data;
> @@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net)
>                       break;
>               }
>               /* We don't need to be notified again. */
> -             if (unlikely((vhost_hlen)))
> -                     /* Skip header. TODO: support TSO. */
> -                     move_iovec_hdr(vq->iov, nvq->hdr, vhost_hlen, in);
> -             else
> -                     /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
> -                      * needed because recvmsg can modify msg_iov. */
> -                     copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in);
> -             iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len);
> +             iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
> +             fixup = msg.msg_iter;
> +             if (unlikely((vhost_hlen))) {
> +                     /* We will supply the header ourselves
> +                      * TODO: support TSO.
> +                      */
> +                     iov_iter_advance(&msg.msg_iter, vhost_hlen);
> +             } 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,
>                                        sock_len, MSG_DONTWAIT | MSG_TRUNC);
>               /* 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);
>                       continue;
>               }
> +             /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
>               if (unlikely(vhost_hlen) &&
> -                 memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0,
> -                                   vhost_hlen)) {
> +                 copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
>                       vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
>                              vq->iov->iov_base);
>                       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) &&
> -                 memcpy_toiovecend(nvq->hdr, (unsigned char *)&headcount,
> -                                   offsetof(typeof(hdr), num_buffers),
> -                                   sizeof hdr.num_buffers)) {
> +                 copy_to_iter(&headcount, 2, &fixup) != 2) {
>                       vq_err(vq, "Failed num_buffers write");
>                       vhost_discard_vq_desc(vq, headcount);
>                       break;
> diff --git a/include/linux/uio.h b/include/linux/uio.h
> index af3439f..02bd8a9 100644
> --- a/include/linux/uio.h
> +++ b/include/linux/uio.h
> @@ -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 offset, int len);
> -int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
> -                   int offset, int len);
> -
>  #endif
> diff --git a/lib/iovec.c b/lib/iovec.c
> index 4a90875..d8f17a9 100644
> --- a/lib/iovec.c
> +++ b/lib/iovec.c
> @@ -3,32 +3,6 @@
>  #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.
>   */
>  
> -- 
> 2.1.4
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to