[PATCH v6] Add mergeable rx buffer support to vhost_net

2010-04-26 Thread David L Stevens
This patch adds mergeable receive buffer support to vhost_net.

+-DLS

Signed-off-by: David L Stevens 

diff -ruNp net-next-v0/drivers/vhost/net.c net-next-v6/drivers/vhost/net.c
--- net-next-v0/drivers/vhost/net.c 2010-04-24 21:36:54.0 -0700
+++ net-next-v6/drivers/vhost/net.c 2010-04-26 01:13:04.0 -0700
@@ -109,7 +109,7 @@ static void handle_tx(struct vhost_net *
};
size_t len, total_len = 0;
int err, wmem;
-   size_t hdr_size;
+   size_t vhost_hlen;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock)
return;
@@ -128,13 +128,13 @@ static void handle_tx(struct vhost_net *
 
if (wmem < sock->sk->sk_sndbuf / 2)
tx_poll_stop(net);
-   hdr_size = vq->hdr_size;
+   vhost_hlen = vq->vhost_hlen;
 
for (;;) {
-   head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-ARRAY_SIZE(vq->iov),
-&out, &in,
-NULL, NULL);
+   head = vhost_get_desc(&net->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov),
+ &out, &in,
+ NULL, NULL);
/* Nothing new?  Wait for eventfd to tell us they refilled. */
if (head == vq->num) {
wmem = atomic_read(&sock->sk->sk_wmem_alloc);
@@ -155,20 +155,20 @@ static void handle_tx(struct vhost_net *
break;
}
/* Skip header. TODO: support TSO. */
-   s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
+   s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, out);
msg.msg_iovlen = out;
len = iov_length(vq->iov, out);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for TX: "
   "%zd expected %zd\n",
-  iov_length(vq->hdr, s), hdr_size);
+  iov_length(vq->hdr, s), vhost_hlen);
break;
}
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
-   vhost_discard_vq_desc(vq);
+   vhost_discard_desc(vq, 1);
tx_poll_start(net, sock);
break;
}
@@ -187,12 +187,25 @@ static void handle_tx(struct vhost_net *
unuse_mm(net->dev.mm);
 }
 
+static int vhost_head_len(struct vhost_virtqueue *vq, struct sock *sk)
+{
+   struct sk_buff *head;
+   int len = 0;
+
+   lock_sock(sk);
+   head = skb_peek(&sk->sk_receive_queue);
+   if (head)
+   len = head->len + vq->sock_hlen;
+   release_sock(sk);
+   return len;
+}
+
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
 static void handle_rx(struct vhost_net *net)
 {
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-   unsigned head, out, in, log, s;
+   unsigned in, log, s;
struct vhost_log *vq_log;
struct msghdr msg = {
.msg_name = NULL,
@@ -203,14 +216,14 @@ static void handle_rx(struct vhost_net *
.msg_flags = MSG_DONTWAIT,
};
 
-   struct virtio_net_hdr hdr = {
-   .flags = 0,
-   .gso_type = VIRTIO_NET_HDR_GSO_NONE
+   struct virtio_net_hdr_mrg_rxbuf hdr = {
+   .hdr.flags = 0,
+   .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
};
 
size_t len, total_len = 0;
-   int err;
-   size_t hdr_size;
+   int err, headcount, datalen;
+   size_t vhost_hlen;
struct socket *sock = rcu_dereference(vq->private_data);
if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
return;
@@ -218,18 +231,19 @@ static void handle_rx(struct vhost_net *
use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
-   hdr_size = vq->hdr_size;
+   vhost_hlen = vq->vhost_hlen;
 
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
 
-   for (;;) {
-   head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-ARRAY_SIZE(vq->iov),
-&out, &in,
-vq_log, &log);
+   while ((datalen = vhost_head_len(vq, sock->sk))) {
+   headcount = vhost_get_desc_n(vq, vq->heads,
+datalen + vhost_hlen,
+  

Re: [PATCH v6] Add mergeable rx buffer support to vhost_net

2010-04-26 Thread Michael S. Tsirkin
On Mon, Apr 26, 2010 at 02:20:52PM -0700, David L Stevens wrote:
> This patch adds mergeable receive buffer support to vhost_net.
> 
>   +-DLS
> 
> Signed-off-by: David L Stevens 

OK, looks good. I still think iovec handling is a bit off,
as commented below.

> diff -ruNp net-next-v0/drivers/vhost/net.c net-next-v6/drivers/vhost/net.c
> --- net-next-v0/drivers/vhost/net.c   2010-04-24 21:36:54.0 -0700
> +++ net-next-v6/drivers/vhost/net.c   2010-04-26 01:13:04.0 -0700
> @@ -109,7 +109,7 @@ static void handle_tx(struct vhost_net *
>   };
>   size_t len, total_len = 0;
>   int err, wmem;
> - size_t hdr_size;
> + size_t vhost_hlen;
>   struct socket *sock = rcu_dereference(vq->private_data);
>   if (!sock)
>   return;
> @@ -128,13 +128,13 @@ static void handle_tx(struct vhost_net *
>  
>   if (wmem < sock->sk->sk_sndbuf / 2)
>   tx_poll_stop(net);
> - hdr_size = vq->hdr_size;
> + vhost_hlen = vq->vhost_hlen;
>  
>   for (;;) {
> - head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
> -  ARRAY_SIZE(vq->iov),
> -  &out, &in,
> -  NULL, NULL);
> + head = vhost_get_desc(&net->dev, vq, vq->iov,
> +   ARRAY_SIZE(vq->iov),
> +   &out, &in,
> +   NULL, NULL);
>   /* Nothing new?  Wait for eventfd to tell us they refilled. */
>   if (head == vq->num) {
>   wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> @@ -155,20 +155,20 @@ static void handle_tx(struct vhost_net *
>   break;
>   }
>   /* Skip header. TODO: support TSO. */
> - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
> + s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, out);
>   msg.msg_iovlen = out;
>   len = iov_length(vq->iov, out);
>   /* Sanity check */
>   if (!len) {
>   vq_err(vq, "Unexpected header len for TX: "
>  "%zd expected %zd\n",
> -iov_length(vq->hdr, s), hdr_size);
> +iov_length(vq->hdr, s), vhost_hlen);
>   break;
>   }
>   /* TODO: Check specific error and bomb out unless ENOBUFS? */
>   err = sock->ops->sendmsg(NULL, sock, &msg, len);
>   if (unlikely(err < 0)) {
> - vhost_discard_vq_desc(vq);
> + vhost_discard_desc(vq, 1);
>   tx_poll_start(net, sock);
>   break;
>   }
> @@ -187,12 +187,25 @@ static void handle_tx(struct vhost_net *
>   unuse_mm(net->dev.mm);
>  }
>  
> +static int vhost_head_len(struct vhost_virtqueue *vq, struct sock *sk)
> +{
> + struct sk_buff *head;
> + int len = 0;
> +
> + lock_sock(sk);
> + head = skb_peek(&sk->sk_receive_queue);
> + if (head)
> + len = head->len + vq->sock_hlen;
> + release_sock(sk);
> + return len;
> +}
> +
>  /* Expects to be always run from workqueue - which acts as
>   * read-size critical section for our kind of RCU. */
>  static void handle_rx(struct vhost_net *net)
>  {
>   struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
> - unsigned head, out, in, log, s;
> + unsigned in, log, s;
>   struct vhost_log *vq_log;
>   struct msghdr msg = {
>   .msg_name = NULL,
> @@ -203,14 +216,14 @@ static void handle_rx(struct vhost_net *
>   .msg_flags = MSG_DONTWAIT,
>   };
>  
> - struct virtio_net_hdr hdr = {
> - .flags = 0,
> - .gso_type = VIRTIO_NET_HDR_GSO_NONE
> + struct virtio_net_hdr_mrg_rxbuf hdr = {
> + .hdr.flags = 0,
> + .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
>   };
>  
>   size_t len, total_len = 0;
> - int err;
> - size_t hdr_size;
> + int err, headcount, datalen;
> + size_t vhost_hlen;
>   struct socket *sock = rcu_dereference(vq->private_data);
>   if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
>   return;
> @@ -218,18 +231,19 @@ static void handle_rx(struct vhost_net *
>   use_mm(net->dev.mm);
>   mutex_lock(&vq->mutex);
>   vhost_disable_notify(vq);
> - hdr_size = vq->hdr_size;
> + vhost_hlen = vq->vhost_hlen;
>  
>   vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
>   vq->log : NULL;
>  
> - for (;;) {
> - head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
> -  ARRAY_SIZE(vq->iov),
> -  &out, &in,
> -  vq_log, &log);
> + while ((datalen