Re: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()

2015-02-03 Thread Al Viro
On Tue, Feb 03, 2015 at 04:21:54PM +0100, Michael S. Tsirkin wrote:
> > Hmm having second thoughts here.
> > Will this modify the iov in vq->iov?
> > If yes, how will recvmsg fill it?
> 
> OK that was just me misunderstanding what the
> function does. As it doesn't modify the iovec itself,
> I think there's no issue, my ack stands.

That, BTW, was the point of switching ->sendmsg() and ->recvmsg() to
iov_iter primitives - not only do memcpy_toiovec() et.al. change the
iovec, the way it's done was protocol-dependent, up to and including
the things like "have sent 60 caller-supplied bytes, iovec modified
with only 6 bytes consumed".  What's worse, on TCP sendmsg we usually
left iovec unchanged, but sometimes it got drained.  Granted, that
happened only after setsockopt() playing caller with TCP_REPAIR (i.e.
checkpoint/restart stuff), but...
--
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


Re: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()

2015-02-03 Thread Michael S. Tsirkin
> Hmm having second thoughts here.
> Will this modify the iov in vq->iov?
> If yes, how will recvmsg fill it?

OK that was just me misunderstanding what the
function does. As it doesn't modify the iovec itself,
I think there's no issue, my ack stands.
--
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


Re: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()

2015-02-03 Thread Michael S. Tsirkin
On Mon, Feb 02, 2015 at 07:59:36AM +, Al Viro wrote:
> From: Al Viro 
> 
> Cc: Michael S. Tsirkin 
> Cc: kvm@vger.kernel.org
> Signed-off-by: Al Viro 
> ---
>  drivers/vhost/net.c | 79 
> ++---
>  include/linux/uio.h |  3 --
>  lib/iovec.c | 26 --
>  3 files changed, 20 insertions(+), 88 deletions(-)
> 
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index d86cc9b..73c0ebf 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,17 @@ 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:


Hmm having second thoughts here.
Will this modify the iov in vq->iov?
If yes, how will recvmsg fill it?




> @@ -643,18 +605,17 @@ static void handle_rx(struct vhost_net *net)
>   vhost_discard_vq_desc(vq, headcount);
>   

Re: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()

2015-02-03 Thread Michael S. Tsirkin
On Mon, Feb 02, 2015 at 07:59:36AM +, Al Viro wrote:
> From: Al Viro 
> 
> Cc: Michael S. Tsirkin 
> Cc: kvm@vger.kernel.org
> Signed-off-by: Al Viro 
> ---

So this made me notice a bug in vhost introduced in 3.19.
I sent a patch for that, this one will have to be
rebased on top. Otherwise:

Acked-by: Michael S. Tsirkin 

But, can you pls copy virtualizat...@lists.linux-foundation.org ?
I think some guys working on virtio might only hang out there.



>  drivers/vhost/net.c | 79 
> ++---
>  include/linux/uio.h |  3 --
>  lib/iovec.c | 26 --
>  3 files changed, 20 insertions(+), 88 deletions(-)
> 
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index d86cc9b..73c0ebf 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,17 @@ 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);
>   /* U