* Re: [PATCHv5] add mergeable receiver buffers support to vhost
From: Michael S. Tsirkin @ 2010-04-24 19:07 UTC (permalink / raw)
To: David L Stevens; +Cc: rusty, kvm, virtualization, netdev
In-Reply-To: <1272053205.3114.3.camel@lab1.dls>
On Fri, Apr 23, 2010 at 01:06:45PM -0700, David L Stevens wrote:
> This patch adds mergeable receive buffers support to vhost.
>
> Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
It seems the logging is wrong. Did you test live migration? Please do.
I think reason for the bug could be you did some cut and paste
from code that was there before 86e9424d7252bae5ad1c17b4b8088193e6b27cbe.
So I put a suggestion on reducing this duplication a bit, below.
Also, I think this patch adds sparse errors: some __user annotations
seem missing. Could you please make your patch apply
on top of patch 'vhost: fix sparse warnings' from
Christoph Hellwig, and then make sure your patch
does not add new sparse errors?
I also wanted to make some coding style tweaks, to make
patch match the style of the rest of the code, I could do
them myself but since there's these issues, and we need another
round, I put them in comments in mail below.
Thanks!
> diff -ruNp net-next-v0/drivers/vhost/net.c net-next-v5/drivers/vhost/net.c
> --- net-next-v0/drivers/vhost/net.c 2010-04-22 11:31:57.000000000 -0700
> +++ net-next-v5/drivers/vhost/net.c 2010-04-22 12:41:17.000000000 -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,18 @@ 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,
checkpatch does not catch this but please add spaces around +.
> + &in, vq_log, &log);
> + if (headcount < 0)
> + break;
> /* OK, now we need to know about added descriptors. */
> - if (head == vq->num) {
> + if (!headcount) {
> if (unlikely(vhost_enable_notify(vq))) {
> /* They have slipped one in as we were
> * doing that: check again. */
> @@ -241,46 +254,54 @@ static void handle_rx(struct vhost_net *
> break;
> }
> /* We don't need to be notified again. */
> - if (out) {
> - vq_err(vq, "Unexpected descriptor format for RX: "
> - "out %d, int %d\n",
> - out, in);
> - break;
> - }
> - /* Skip header. TODO: support TSO/mergeable rx buffers. */
> - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
> + /* Skip header. TODO: support TSO. */
> + s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
> msg.msg_iovlen = in;
> len = iov_length(vq->iov, in);
> /* Sanity check */
> if (!len) {
> vq_err(vq, "Unexpected header len for RX: "
> "%zd expected %zd\n",
> - iov_length(vq->hdr, s), hdr_size);
> + iov_length(vq->hdr, s), vhost_hlen);
> break;
> }
> err = sock->ops->recvmsg(NULL, sock, &msg,
> len, MSG_DONTWAIT | MSG_TRUNC);
> /* TODO: Check specific error and bomb out unless EAGAIN? */
> if (err < 0) {
> - vhost_discard_vq_desc(vq);
> + vhost_discard_desc(vq, headcount);
> break;
> }
> - /* TODO: Should check and handle checksum. */
> - if (err > len) {
> - pr_err("Discarded truncated rx packet: "
> - " len %d > %zd\n", err, len);
> - vhost_discard_vq_desc(vq);
> + if (err != datalen) {
> + pr_err("Discarded rx packet: "
> + " len %d, expected %zd\n", err, datalen);
> + vhost_discard_desc(vq, headcount);
> continue;
> }
> len = err;
> - err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
> + err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr,
> + vhost_hlen);
> if (err) {
> vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
> vq->iov->iov_base, err);
> break;
> }
> - len += hdr_size;
> - vhost_add_used_and_signal(&net->dev, vq, head, len);
> + /* TODO: Should check and handle checksum. */
> + if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
> + struct virtio_net_hdr_mrg_rxbuf hdr;
> + struct iovec *iov = vhost_hlen ? vq->hdr : vq->iov;
> +
> + if (memcpy_toiovecend(iov, (unsigned char *)&headcount,
> + offsetof(typeof(hdr), num_buffers),
> + sizeof(hdr.num_buffers))) {
> + vq_err(vq, "Failed num_buffers write");
> + vhost_discard_desc(vq, headcount);
> + break;
> + }
> + }
> + len += vhost_hlen;
> + vhost_add_used_and_signal_n(&net->dev, vq, vq->heads,
> + headcount);
> if (unlikely(vq_log))
> vhost_log_write(vq, vq_log, log, len);
> total_len += len;
> @@ -561,9 +582,24 @@ done:
>
> static int vhost_net_set_features(struct vhost_net *n, u64 features)
> {
> - size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
> - sizeof(struct virtio_net_hdr) : 0;
> + size_t vhost_hlen;
> + size_t sock_hlen;
> int i;
> +
> + if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
> + /* vhost provides vnet_hdr */
> + vhost_hlen = sizeof(struct virtio_net_hdr);
> + if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
> + vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> + sock_hlen = 0;
> + } else {
> + /* socket provides vnet_hdr */
> + vhost_hlen = 0;
> + if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
> + sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> + else
> + sock_hlen = sizeof(struct virtio_net_hdr);
> + }
> mutex_lock(&n->dev.mutex);
> if ((features & (1 << VHOST_F_LOG_ALL)) &&
> !vhost_log_access_ok(&n->dev)) {
> @@ -574,7 +610,8 @@ static int vhost_net_set_features(struct
> smp_wmb();
> for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
> mutex_lock(&n->vqs[i].mutex);
> - n->vqs[i].hdr_size = hdr_size;
> + n->vqs[i].vhost_hlen = vhost_hlen;
> + n->vqs[i].sock_hlen = sock_hlen;
> mutex_unlock(&n->vqs[i].mutex);
> }
> vhost_net_flush(n);
> diff -ruNp net-next-v0/drivers/vhost/vhost.c net-next-v5/drivers/vhost/vhost.c
> --- net-next-v0/drivers/vhost/vhost.c 2010-04-22 11:31:57.000000000 -0700
> +++ net-next-v5/drivers/vhost/vhost.c 2010-04-22 12:19:59.000000000 -0700
> @@ -114,7 +114,8 @@ static void vhost_vq_reset(struct vhost_
> vq->used_flags = 0;
> vq->log_used = false;
> vq->log_addr = -1ull;
> - vq->hdr_size = 0;
> + vq->vhost_hlen = 0;
> + vq->sock_hlen = 0;
> vq->private_data = NULL;
> vq->log_base = NULL;
> vq->error_ctx = NULL;
> @@ -861,6 +862,53 @@ static unsigned get_indirect(struct vhos
> return 0;
> }
>
> +/* This is a multi-buffer version of vhost_get_vq_desc
> + * @vq - the relevant virtqueue
> + * datalen - data length we'll be reading
> + * @iovcount - returned count of io vectors we fill
> + * @log - vhost log
> + * @log_num - log offset
> + * returns number of buffer heads allocated, negative on error
> + */
> +int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + int datalen, int *iovcount, struct vhost_log *log,
> + unsigned int *log_num)
> +{
> + int out, in;
> + int seg = 0; /* iov index */
In rest of code, I always put comments above the commented code,
not to the right of it.
> + int hc = 0; /* head count */
Maybe just call the variable head_count? That'd make the
comment unnecessary.
> + int rv;
rest of code uses r or ret for such variables.
> +
> + while (datalen > 0) {
> + if (hc >= VHOST_NET_MAX_SG) {
> + rv = -ENOBUFS;
> + goto err;
> + }
> + heads[hc].id = vhost_get_desc(vq->dev, vq, vq->iov+seg,
> + ARRAY_SIZE(vq->iov)-seg, &out,
same here, spaces around + and -
> + &in, log, log_num);
> + if (heads[hc].id == vq->num) {
> + rv = 0;
> + goto err;
> + }
> + if (out || in <= 0) {
> + vq_err(vq, "unexpected descriptor format for RX: "
> + "out %d, in %d\n", out, in);
> + rv = -EINVAL;
> + goto err;
> + }
> + heads[hc].len = iov_length(vq->iov+seg, in);
and here
> + datalen -= heads[hc].len;
> + hc++;
I use ++x in the rest of the code wher I don't care for
the old value.
> + seg += in;
> + }
> + *iovcount = seg;
> + return hc;
> +err:
> + vhost_discard_desc(vq, hc);
> + return rv;
> +}
> +
> /* This looks in the virtqueue and for the first available buffer, and converts
> * it to an iovec for convenient access. Since descriptors consist of some
> * number of output then some number of input descriptors, it's actually two
> @@ -868,7 +916,7 @@ static unsigned get_indirect(struct vhos
> *
> * This function returns the descriptor number found, or vq->num (which
> * is never a valid descriptor number) if none was found. */
> -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> +unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> struct iovec iov[], unsigned int iov_size,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num)
> @@ -986,9 +1034,9 @@ unsigned vhost_get_vq_desc(struct vhost_
> }
>
> /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
> -void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
> +void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
> {
> - vq->last_avail_idx--;
> + vq->last_avail_idx -= n;
> }
>
> /* After we've used one of their buffers, we tell them about it. We'll then
> @@ -1017,6 +1065,54 @@ int vhost_add_used(struct vhost_virtqueu
> if (unlikely(vq->log_used)) {
> /* Make sure data is seen before log. */
> smp_wmb();
> + log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
> + (vq->last_used_idx % vq->num),
> + sizeof *vq->used->ring);
> + log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
> + if (vq->log_ctx)
> + eventfd_signal(vq->log_ctx, 1);
> + }
> + vq->last_used_idx++;
> + return 0;
The above looks like a copy from an old version of vhost.
> +}
> +
> +/* After we've used one of their buffers, we tell them about it. We'll then
> + * want to notify the guest, using eventfd. */
> +int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + int count)
please align int at least to the right of (.
> +{
> + struct vring_used_elem *used;
> + int start, n;
> +
> + if (count <= 0)
> + return -EINVAL;
Is the above necessary?
Just make count unsigned for clarity?
> +
> + start = vq->last_used_idx % vq->num;
> + if (vq->num - start < count)
> + n = vq->num - start;
> + else
> + n = count;
I'd say use min, or reorder code as I suggest below
to only have a single if.
> + used = vq->used->ring + start;
> + if (copy_to_user(used, heads, sizeof(heads[0])*n)) {
Pls put spaces around *
Also I'd prefer sizeof *used here instead of sizeof(heads[0]),
it's shorter. My style is also to put () after sizeof only
if the argument is a type, and order the expression
to make precedence not matter. So we'd end up with:
n * sizeof *used.
> + vq_err(vq, "Failed to write used");
> + return -EFAULT;
> + }
> + if (n < count) { /* wrapped the ring */
In rest of code, I always put comments above the commented code,
not to the right of it.
The only case we can have n < count is wrap-around,
so I find this a roundabout way to code this up, and we
end up with test for same condition, which makes the
code fragile (ignoring performance impact).
Also note need for extra logging as explained below.
Maybe it's cleanest to have static __vhost_add_used_n which assumes
no wrap-around, and then just call:
vhost_add_used_n()
if (unlikely(n < count)) {
if (r = __vhost_add_used_n())
return r;
heads += n;
count -= n;
}
return __vhost_add_used_n()
this would do an extra write into used index,
but this is almost freem
> + used = vq->used->ring;
> + if (copy_to_user(used, heads+n, sizeof(heads[0])*(count-n))) {
spaces around + and *
> + vq_err(vq, "Failed to write used");
> + return -EFAULT;
> + }
> + }
> + /* Make sure buffer is written before we update index. */
> + smp_wmb();
> + if (put_user(vq->last_used_idx+count, &vq->used->idx)) {
and here
> + vq_err(vq, "Failed to increment used idx");
> + return -EFAULT;
> + }
> + if (unlikely(vq->log_used)) {
> + /* Make sure data is seen before log. */
> + smp_wmb();
> /* Log used ring entry write. */
> log_write(vq->log_base,
> vq->log_addr +
this uses 'used' pointer, but I think it's wrong in case
of wrap-around. I think we'll need extra logging for
wrap-around. That would be 3 copies of identical code:
maybe add a function?
static void vhost_log_used(struct vhost_virtqueue *vq,
struct vring_used_elem __user *used)
{
/* Make sure data is seen before log. */
smp_wmb();
/* Log used ring entry write. */
log_write(vq->log_base,
vq->log_addr +
((void __user *)used - (void __user *)vq->used),
sizeof *used);
/* Log used index update. */
log_write(vq->log_base,
vq->log_addr + offsetof(struct vring_used, idx),
sizeof vq->used->idx);
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
> @@ -1029,7 +1125,7 @@ int vhost_add_used(struct vhost_virtqueu
> if (vq->log_ctx)
> eventfd_signal(vq->log_ctx, 1);
> }
> - vq->last_used_idx++;
> + vq->last_used_idx += count;
> return 0;
> }
>
> @@ -1062,6 +1158,15 @@ void vhost_add_used_and_signal(struct vh
> vhost_signal(dev, vq);
> }
>
> +/* multi-buffer version of vhost_add_used_and_signal */
> +void vhost_add_used_and_signal_n(struct vhost_dev *dev,
> + struct vhost_virtqueue *vq,
> + struct vring_used_elem *heads, int count)
> +{
> + vhost_add_used_n(vq, heads, count);
> + vhost_signal(dev, vq);
> +}
> +
> /* OK, now we need to know about added descriptors. */
> bool vhost_enable_notify(struct vhost_virtqueue *vq)
> {
> @@ -1086,7 +1191,7 @@ bool vhost_enable_notify(struct vhost_vi
> return false;
> }
>
> - return avail_idx != vq->last_avail_idx;
> + return avail_idx != vq->avail_idx;
> }
>
> /* We don't need to be notified again. */
> diff -ruNp net-next-v0/drivers/vhost/vhost.h net-next-v5/drivers/vhost/vhost.h
> --- net-next-v0/drivers/vhost/vhost.h 2010-03-22 12:04:38.000000000 -0700
> +++ net-next-v5/drivers/vhost/vhost.h 2010-04-22 11:35:54.000000000 -0700
> @@ -84,7 +84,9 @@ struct vhost_virtqueue {
> struct iovec indirect[VHOST_NET_MAX_SG];
> struct iovec iov[VHOST_NET_MAX_SG];
> struct iovec hdr[VHOST_NET_MAX_SG];
> - size_t hdr_size;
> + size_t vhost_hlen;
> + size_t sock_hlen;
> + struct vring_used_elem heads[VHOST_NET_MAX_SG];
> /* We use a kind of RCU to access private pointer.
> * All readers access it from workqueue, which makes it possible to
> * flush the workqueue instead of synchronize_rcu. Therefore readers do
> @@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
> int vhost_vq_access_ok(struct vhost_virtqueue *vq);
> int vhost_log_access_ok(struct vhost_dev *);
>
> -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
> +int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + int datalen, int *iovcount, struct vhost_log *log,
> + unsigned int *log_num);
> +unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
> struct iovec iov[], unsigned int iov_count,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num);
> -void vhost_discard_vq_desc(struct vhost_virtqueue *);
> +void vhost_discard_desc(struct vhost_virtqueue *, int);
>
> int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
> -void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> +int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + int count);
> void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
> - unsigned int head, int len);
> + unsigned int id, int len);
> +void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
> + struct vring_used_elem *heads, int count);
> +void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> void vhost_disable_notify(struct vhost_virtqueue *);
> bool vhost_enable_notify(struct vhost_virtqueue *);
>
> @@ -149,7 +158,8 @@ enum {
> VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
> (1 << VIRTIO_RING_F_INDIRECT_DESC) |
> (1 << VHOST_F_LOG_ALL) |
> - (1 << VHOST_NET_F_VIRTIO_NET_HDR),
> + (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
> + (1 << VIRTIO_NET_F_MRG_RXBUF),
> };
>
> static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
>
^ permalink raw reply
* [PATCHv5] add mergeable receiver buffers support to vhost
From: David L Stevens @ 2010-04-23 20:06 UTC (permalink / raw)
To: mst, rusty, kvm, virtualization; +Cc: netdev
This patch adds mergeable receive buffers support to vhost.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
diff -ruNp net-next-v0/drivers/vhost/net.c net-next-v5/drivers/vhost/net.c
--- net-next-v0/drivers/vhost/net.c 2010-04-22 11:31:57.000000000 -0700
+++ net-next-v5/drivers/vhost/net.c 2010-04-22 12:41:17.000000000 -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,18 @@ 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,
+ &in, vq_log, &log);
+ if (headcount < 0)
+ break;
/* OK, now we need to know about added descriptors. */
- if (head == vq->num) {
+ if (!headcount) {
if (unlikely(vhost_enable_notify(vq))) {
/* They have slipped one in as we were
* doing that: check again. */
@@ -241,46 +254,54 @@ static void handle_rx(struct vhost_net *
break;
}
/* We don't need to be notified again. */
- if (out) {
- vq_err(vq, "Unexpected descriptor format for RX: "
- "out %d, int %d\n",
- out, in);
- break;
- }
- /* Skip header. TODO: support TSO/mergeable rx buffers. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+ /* Skip header. TODO: support TSO. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ iov_length(vq->hdr, s), vhost_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard_desc(vq, headcount);
break;
}
- /* TODO: Should check and handle checksum. */
- if (err > len) {
- pr_err("Discarded truncated rx packet: "
- " len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ if (err != datalen) {
+ pr_err("Discarded rx packet: "
+ " len %d, expected %zd\n", err, datalen);
+ vhost_discard_desc(vq, headcount);
continue;
}
len = err;
- err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+ err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr,
+ vhost_hlen);
if (err) {
vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
vq->iov->iov_base, err);
break;
}
- len += hdr_size;
- vhost_add_used_and_signal(&net->dev, vq, head, len);
+ /* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
+ struct virtio_net_hdr_mrg_rxbuf hdr;
+ struct iovec *iov = vhost_hlen ? vq->hdr : vq->iov;
+
+ if (memcpy_toiovecend(iov, (unsigned char *)&headcount,
+ offsetof(typeof(hdr), num_buffers),
+ sizeof(hdr.num_buffers))) {
+ vq_err(vq, "Failed num_buffers write");
+ vhost_discard_desc(vq, headcount);
+ break;
+ }
+ }
+ len += vhost_hlen;
+ vhost_add_used_and_signal_n(&net->dev, vq, vq->heads,
+ headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
total_len += len;
@@ -561,9 +582,24 @@ done:
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
+ size_t vhost_hlen;
+ size_t sock_hlen;
int i;
+
+ if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
+ /* vhost provides vnet_hdr */
+ vhost_hlen = sizeof(struct virtio_net_hdr);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ sock_hlen = 0;
+ } else {
+ /* socket provides vnet_hdr */
+ vhost_hlen = 0;
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ sock_hlen = sizeof(struct virtio_net_hdr);
+ }
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
!vhost_log_access_ok(&n->dev)) {
@@ -574,7 +610,8 @@ static int vhost_net_set_features(struct
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ n->vqs[i].vhost_hlen = vhost_hlen;
+ n->vqs[i].sock_hlen = sock_hlen;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
diff -ruNp net-next-v0/drivers/vhost/vhost.c net-next-v5/drivers/vhost/vhost.c
--- net-next-v0/drivers/vhost/vhost.c 2010-04-22 11:31:57.000000000 -0700
+++ net-next-v5/drivers/vhost/vhost.c 2010-04-22 12:19:59.000000000 -0700
@@ -114,7 +114,8 @@ static void vhost_vq_reset(struct vhost_
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->vhost_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -861,6 +862,53 @@ static unsigned get_indirect(struct vhos
return 0;
}
+/* This is a multi-buffer version of vhost_get_vq_desc
+ * @vq - the relevant virtqueue
+ * datalen - data length we'll be reading
+ * @iovcount - returned count of io vectors we fill
+ * @log - vhost log
+ * @log_num - log offset
+ * returns number of buffer heads allocated, negative on error
+ */
+int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num)
+{
+ int out, in;
+ int seg = 0; /* iov index */
+ int hc = 0; /* head count */
+ int rv;
+
+ while (datalen > 0) {
+ if (hc >= VHOST_NET_MAX_SG) {
+ rv = -ENOBUFS;
+ goto err;
+ }
+ heads[hc].id = vhost_get_desc(vq->dev, vq, vq->iov+seg,
+ ARRAY_SIZE(vq->iov)-seg, &out,
+ &in, log, log_num);
+ if (heads[hc].id == vq->num) {
+ rv = 0;
+ goto err;
+ }
+ if (out || in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ rv = -EINVAL;
+ goto err;
+ }
+ heads[hc].len = iov_length(vq->iov+seg, in);
+ datalen -= heads[hc].len;
+ hc++;
+ seg += in;
+ }
+ *iovcount = seg;
+ return hc;
+err:
+ vhost_discard_desc(vq, hc);
+ return rv;
+}
+
/* This looks in the virtqueue and for the first available buffer, and converts
* it to an iovec for convenient access. Since descriptors consist of some
* number of output then some number of input descriptors, it's actually two
@@ -868,7 +916,7 @@ static unsigned get_indirect(struct vhos
*
* This function returns the descriptor number found, or vq->num (which
* is never a valid descriptor number) if none was found. */
-unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
struct iovec iov[], unsigned int iov_size,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num)
@@ -986,9 +1034,9 @@ unsigned vhost_get_vq_desc(struct vhost_
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll then
@@ -1017,6 +1065,54 @@ int vhost_add_used(struct vhost_virtqueu
if (unlikely(vq->log_used)) {
/* Make sure data is seen before log. */
smp_wmb();
+ log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+ (vq->last_used_idx % vq->num),
+ sizeof *vq->used->ring);
+ log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ vq->last_used_idx++;
+ return 0;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int count)
+{
+ struct vring_used_elem *used;
+ int start, n;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ start = vq->last_used_idx % vq->num;
+ if (vq->num - start < count)
+ n = vq->num - start;
+ else
+ n = count;
+ used = vq->used->ring + start;
+ if (copy_to_user(used, heads, sizeof(heads[0])*n)) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ if (n < count) { /* wrapped the ring */
+ used = vq->used->ring;
+ if (copy_to_user(used, heads+n, sizeof(heads[0])*(count-n))) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ }
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ if (put_user(vq->last_used_idx+count, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ smp_wmb();
/* Log used ring entry write. */
log_write(vq->log_base,
vq->log_addr +
@@ -1029,7 +1125,7 @@ int vhost_add_used(struct vhost_virtqueu
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
- vq->last_used_idx++;
+ vq->last_used_idx += count;
return 0;
}
@@ -1062,6 +1158,15 @@ void vhost_add_used_and_signal(struct vh
vhost_signal(dev, vq);
}
+/* multi-buffer version of vhost_add_used_and_signal */
+void vhost_add_used_and_signal_n(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads, int count)
+{
+ vhost_add_used_n(vq, heads, count);
+ vhost_signal(dev, vq);
+}
+
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_virtqueue *vq)
{
@@ -1086,7 +1191,7 @@ bool vhost_enable_notify(struct vhost_vi
return false;
}
- return avail_idx != vq->last_avail_idx;
+ return avail_idx != vq->avail_idx;
}
/* We don't need to be notified again. */
diff -ruNp net-next-v0/drivers/vhost/vhost.h net-next-v5/drivers/vhost/vhost.h
--- net-next-v0/drivers/vhost/vhost.h 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v5/drivers/vhost/vhost.h 2010-04-22 11:35:54.000000000 -0700
@@ -84,7 +84,9 @@ struct vhost_virtqueue {
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t vhost_hlen;
+ size_t sock_hlen;
+ struct vring_used_elem heads[VHOST_NET_MAX_SG];
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
* flush the workqueue instead of synchronize_rcu. Therefore readers do
@@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
-unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num);
+unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard_desc(struct vhost_virtqueue *, int);
int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
- unsigned int head, int len);
+ unsigned int id, int len);
+void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
+ struct vring_used_elem *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
@@ -149,7 +158,8 @@ enum {
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
^ permalink raw reply
* Linux Plumbers Conference 2010 - call for tracks
From: Jes Sorensen @ 2010-04-23 9:53 UTC (permalink / raw)
To: QEMU Developers, KVM General, virtualization
Hi,
I am organizing a Virtualization track at LPC 2010 (Linux Plumbers
Conference 2010). Please see the official call for tracks below.
LPC is particular well suited for work in progress and subjects that
needs discussion and collaboration between communities, for example
between KVM/QEMU and the Linux Kernel community. We expect strong
participation of kernel developers at LPC, and likely also from the
desktop community (GNOME/KDE/Xorg).
If you have a virtualization related project proposal, please submit it
using the information below. Note this is focused on general Linux
Virtualization, it is not limited to a specific hypervisor.
Subjects could be in the area of (but not limited to):
- Kernel <-> KVM/QEMU interaction
- IO Performance improvements
- NUMA awareness
- Migration
- Support for new hardware features, and/or provide guest access to
these features.
- Virtualization management, user interfaces, and desktop integration
If you have questions related to this track, feel free to ask
lpc-planning@linuxplumbersconf.org or email me directly.
Please feel free to forward this message to other mailing lists or
people for whom you feel it would be relevant.
Best regards,
Jes
Linux Plumbers Conference 2010
Call for Tracks
This year, Linux Plumbers Conference will take place in Cambridge, MA
on November 3-5, 2010. Unlike more traditional conferences, the
Plumbers conference is not structured around presentations of
completed work, or problems and solutions confined to a single
subsystem or layer of the Linux ecosystem. Rather the Plumbers
Conference encourages BOFs type meetings and brainstorming sessions
where technical experts from different areas and leaders in the Linux
and Open Source world can get together and discuss how to make
progress towards the solution of interdisciplinary multifaceted
problems spanning multiple components of the Linux system. In some
sense, the Plumbers Conference is really more of a workshop.
The program committee for the Linux Plumbers Conference is looking for
proposals for the "tracks" that will be run during the Plumbers
Conference.
To do that, we are looking for "problem statements": things that could
be improved in Linux that cross multiple interfaces or other project
boundaries (if you can solve it yourself inside a single project,
please, don't let us stop you --- get hacking!). We are looking for
problems that require collaboration and face-to-face communication
across multiple teams and open source projects. These problems could
apply to anywhere Linux is used: Linux on the Desktop, Linux on Mobile
devices, Linux on servers, etc.
For example, if in order to get better performance, we need to get
better information about low-level devices from the kernel, and that
needs to be utilized by file system utilities, and the user needs to
be able to involved by exposing options at the UI level in control
panels and distribution installers --- the Plumbers conference might
be a great place to get everyone in the same room for half a day to
solve this particular problem.
Along with your problem statements or track ideas, please list the
projects which and/or key individuals who ideally should be present,
and who might be a good person or persons to run such a conference
track.
If you have any thoughts or contributions, you can either
* discuss them on this Linux Weekly News page:
http://lwn.net/Articles/lpc2010-cfi/
* add the proposed topic to the Topics wiki page:
http://wiki.linuxplumbersconf.org/2010:topics
* send e-mail to: lpc-planning@linuxplumbersconf.org
Many thanks for helping to make Linux an even better platform!
The 2010 LPC Committee
Note: The event will be co-located with the Linux Kernel Summit which
will be held earlier that week.
Please feel free to forward this announcements to any communities or
mailing lists where you think it would be appropriate.
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: David Stevens @ 2010-04-22 17:59 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: kvm, virtualization
In-Reply-To: <20100422174349.GA1926@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 878 bytes --]
"Michael S. Tsirkin" <mst@redhat.com> wrote on 04/22/2010 10:43:49 AM:
> On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> > This patch adds the mergeable RX buffers feature to vhost.
> >
> > Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
>
> BTW, which userspace should I use for testing this?
I use the qemu-kvm patch to your git tree that I posted
a while back (also attached). And it needs your TUNSETVNETHDRSIZE
ioctl in the kernel as well. Also, I added the TUN ioctl
defines to /usr/include for this to pick up (it compiles, but
won't do the ioctl's without that); will get back
to that patch per your comments next.
[also correction: I said 10-20% guest to host, I meant host-to-guest
(ie, the receiver side). h2g appears improved too, but not as
much)]
+-DLS
[-- Attachment #2: qemu-MRXB-2.patch --]
[-- Type: application/octet-stream, Size: 2755 bytes --]
diff -ruNp qemu-kvm.mst/hw/vhost_net.c qemu-kvm.dls/hw/vhost_net.c
--- qemu-kvm.mst/hw/vhost_net.c 2010-03-03 13:39:07.000000000 -0800
+++ qemu-kvm.dls/hw/vhost_net.c 2010-03-29 20:37:34.000000000 -0700
@@ -5,6 +5,7 @@
#include <sys/ioctl.h>
#include <linux/vhost.h>
#include <linux/virtio_ring.h>
+#include <linux/if_tun.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
@@ -38,15 +39,6 @@ unsigned vhost_net_get_features(struct v
return features;
}
-void vhost_net_ack_features(struct vhost_net *net, unsigned features)
-{
- net->dev.acked_features = net->dev.backend_features;
- if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))
- net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC))
- net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
-}
-
static int vhost_net_get_fd(VLANClientState *backend)
{
switch (backend->info->type) {
@@ -58,6 +50,25 @@ static int vhost_net_get_fd(VLANClientSt
}
}
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+ int vnet_hdr_sz = sizeof(struct virtio_net_hdr);
+
+ net->dev.acked_features = net->dev.backend_features;
+ if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))
+ net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC))
+ net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+ vnet_hdr_sz = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ }
+#ifdef TUNSETVNETHDRSZ
+ if (ioctl(vhost_net_get_fd(net->vc), TUNSETVNETHDRSZ, &vnet_hdr_sz) < 0)
+ perror("TUNSETVNETHDRSZ");
+#endif /* TUNSETVNETHDRSZ */
+}
+
struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
{
int r;
diff -ruNp qemu-kvm.mst/hw/virtio-net.c qemu-kvm.dls/hw/virtio-net.c
--- qemu-kvm.mst/hw/virtio-net.c 2010-03-03 13:39:07.000000000 -0800
+++ qemu-kvm.dls/hw/virtio-net.c 2010-03-29 16:15:46.000000000 -0700
@@ -211,12 +211,16 @@ static void virtio_net_set_features(Virt
n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
if (n->has_vnet_hdr) {
+ struct vhost_net *vhost_net = tap_get_vhost_net(n->nic->nc.peer);
+
tap_set_offload(n->nic->nc.peer,
(features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
(features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
(features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
(features >> VIRTIO_NET_F_GUEST_ECN) & 1,
(features >> VIRTIO_NET_F_GUEST_UFO) & 1);
+ if (vhost_net)
+ vhost_net_ack_features(vhost_net, features);
}
}
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: Michael S. Tsirkin @ 2010-04-22 17:58 UTC (permalink / raw)
To: David Stevens; +Cc: kvm, virtualization
In-Reply-To: <OF4D87C139.FBE240E7-ON8825770D.0061E3C3-8825770D.0062DEBC@us.ibm.com>
On Thu, Apr 22, 2010 at 11:59:55AM -0600, David Stevens wrote:
> "Michael S. Tsirkin" <mst@redhat.com> wrote on 04/22/2010 10:43:49 AM:
>
> > On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> > > This patch adds the mergeable RX buffers feature to vhost.
> > >
> > > Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
> >
> > BTW, which userspace should I use for testing this?
>
> I use the qemu-kvm patch to your git tree that I posted
> a while back (also attached).
Doesn't apply, probably also corrupted.
Could you put it up on dropbox please?
> And it needs your TUNSETVNETHDRSIZE
> ioctl in the kernel as well. Also, I added the TUN ioctl
> defines to /usr/include for this to pick up (it compiles, but
> won't do the ioctl's without that); will get back
> to that patch per your comments next.
>
> [also correction: I said 10-20% guest to host, I meant host-to-guest
> (ie, the receiver side). h2g appears improved too, but not as
> much)]
>
> +-DLS
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: Michael S. Tsirkin @ 2010-04-22 17:49 UTC (permalink / raw)
To: David Stevens; +Cc: kvm, virtualization
In-Reply-To: <OF97D3792D.AFC89622-ON8825770D.0060EE0B-8825770D.0061B5E1@us.ibm.com>
On Thu, Apr 22, 2010 at 11:47:15AM -0600, David Stevens wrote:
> "Michael S. Tsirkin" <mst@redhat.com> wrote on 04/22/2010 05:02:25 AM:
>
> > On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> > > This patch adds the mergeable RX buffers feature to vhost.
> > >
> > > Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
> >
> > Looks pretty clean to me.
> > Could you send a checkpatch-clean version please?
>
> The original passes checkpatch already, but I guess I must
> still be getting whitespace mangling if it didn't for you. (sigh)
> Here it is as an attachment:
No good either. I thought you managed to run sendmail somewhere?
Failing that, put it on dropbox and let me know.
See http://kbase.redhat.com/faq/docs/DOC-2113
--
MST
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: David Stevens @ 2010-04-22 17:47 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: kvm, virtualization
In-Reply-To: <20100422120225.GA31642@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 928 bytes --]
"Michael S. Tsirkin" <mst@redhat.com> wrote on 04/22/2010 05:02:25 AM:
> On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> > This patch adds the mergeable RX buffers feature to vhost.
> >
> > Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
>
> Looks pretty clean to me.
> Could you send a checkpatch-clean version please?
The original passes checkpatch already, but I guess I must
still be getting whitespace mangling if it didn't for you. (sigh)
Here it is as an attachment:
> We should also check performance implications.
> Do you have any data?
I'm getting on the order of 10-20% improvement in
throughput over stock vhost guest to host, but I do see
a lot of variability in the results, even with no KVM
and just over loopback. I don't know where that's coming
from, but I'll do some runs and post.
Thanks for all the reviews!
+-DLS
[-- Attachment #2: MRXBv4.patch --]
[-- Type: application/octet-stream, Size: 15393 bytes --]
diff -ruNp net-next-p0/drivers/vhost/net.c net-next-v4/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/net.c 2010-04-19 14:23:38.000000000 -0700
@@ -108,7 +108,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;
@@ -127,13 +127,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);
@@ -154,20 +154,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;
}
@@ -186,12 +186,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,
@@ -202,14 +215,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;
@@ -217,18 +230,18 @@ 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,
+ &in, vq_log, &log);
+ if (headcount < 0)
+ break;
/* OK, now we need to know about added descriptors. */
- if (head == vq->num) {
+ if (!headcount) {
if (unlikely(vhost_enable_notify(vq))) {
/* They have slipped one in as we were
* doing that: check again. */
@@ -240,46 +253,52 @@ static void handle_rx(struct vhost_net *
break;
}
/* We don't need to be notified again. */
- if (out) {
- vq_err(vq, "Unexpected descriptor format for RX: "
- "out %d, int %d\n",
- out, in);
- break;
- }
- /* Skip header. TODO: support TSO/mergeable rx buffers. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+ /* Skip header. TODO: support TSO. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ iov_length(vq->hdr, s), vhost_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard_desc(vq, headcount);
break;
}
- /* TODO: Should check and handle checksum. */
- if (err > len) {
- pr_err("Discarded truncated rx packet: "
- " len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ if (err != datalen) {
+ pr_err("Discarded rx packet: "
+ " len %d, expected %zd\n", err, datalen);
+ vhost_discard_desc(vq, headcount);
continue;
}
len = err;
- err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+ err = memcpy_toiovec(vq->hdr,(unsigned char *)&hdr, vhost_hlen);
if (err) {
vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
vq->iov->iov_base, err);
break;
}
- len += hdr_size;
- vhost_add_used_and_signal(&net->dev, vq, head, len);
+ /* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
+ struct virtio_net_hdr_mrg_rxbuf hdr;
+ struct iovec *iov = vhost_hlen ? vq->hdr : vq->iov;
+
+ if (memcpy_toiovecend(iov, (unsigned char *)&headcount,
+ offsetof(typeof(hdr),num_buffers),
+ sizeof(hdr.num_buffers))) {
+ vq_err(vq, "Failed num_buffers write");
+ vhost_discard_desc(vq, headcount);
+ break;
+ }
+ }
+ len += vhost_hlen;
+ vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
total_len += len;
@@ -560,9 +579,24 @@ done:
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
+ size_t vhost_hlen;
+ size_t sock_hlen;
int i;
+
+ if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
+ /* vhost provides vnet_hdr */
+ vhost_hlen = sizeof(struct virtio_net_hdr);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ sock_hlen = 0;
+ } else {
+ /* socket provides vnet_hdr */
+ vhost_hlen = 0;
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ sock_hlen = sizeof(struct virtio_net_hdr);
+ }
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
!vhost_log_access_ok(&n->dev)) {
@@ -573,7 +607,8 @@ static int vhost_net_set_features(struct
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ n->vqs[i].vhost_hlen = vhost_hlen;
+ n->vqs[i].sock_hlen = sock_hlen;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
diff -ruNp net-next-p0/drivers/vhost/vhost.c net-next-v4/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/vhost.c 2010-04-19 14:29:55.000000000 -0700
@@ -113,7 +113,8 @@ static void vhost_vq_reset(struct vhost_
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->vhost_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -856,6 +857,53 @@ static unsigned get_indirect(struct vhos
return 0;
}
+/* This is a multi-buffer version of vhost_get_vq_desc
+ * @vq - the relevant virtqueue
+ * datalen - data length we'll be reading
+ * @iovcount - returned count of io vectors we fill
+ * @log - vhost log
+ * @log_num - log offset
+ * returns number of buffer heads allocated, negative on error
+ */
+int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num)
+{
+ int out, in;
+ int seg = 0; /* iov index */
+ int hc = 0; /* head count */
+ int rv;
+
+ while (datalen > 0) {
+ if (hc >= VHOST_NET_MAX_SG) {
+ rv = -ENOBUFS;
+ goto err;
+ }
+ heads[hc].id = vhost_get_desc(vq->dev, vq, vq->iov+seg,
+ ARRAY_SIZE(vq->iov)-seg, &out,
+ &in, log, log_num);
+ if (heads[hc].id == vq->num) {
+ rv = 0;
+ goto err;
+ }
+ if (out || in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ rv = -EINVAL;
+ goto err;
+ }
+ heads[hc].len = iov_length(vq->iov+seg, in);
+ datalen -= heads[hc].len;
+ hc++;
+ seg += in;
+ }
+ *iovcount = seg;
+ return hc;
+err:
+ vhost_discard_desc(vq, hc);
+ return rv;
+}
+
/* This looks in the virtqueue and for the first available buffer, and converts
* it to an iovec for convenient access. Since descriptors consist of some
* number of output then some number of input descriptors, it's actually two
@@ -863,7 +911,7 @@ static unsigned get_indirect(struct vhos
*
* This function returns the descriptor number found, or vq->num (which
* is never a valid descriptor number) if none was found. */
-unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
struct iovec iov[], unsigned int iov_size,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num)
@@ -981,9 +1029,9 @@ unsigned vhost_get_vq_desc(struct vhost_
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll then
@@ -1012,6 +1060,54 @@ int vhost_add_used(struct vhost_virtqueu
if (unlikely(vq->log_used)) {
/* Make sure data is seen before log. */
smp_wmb();
+ log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+ (vq->last_used_idx % vq->num),
+ sizeof *vq->used->ring);
+ log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ vq->last_used_idx++;
+ return 0;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int count)
+{
+ struct vring_used_elem *used;
+ int start, n;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ start = vq->last_used_idx % vq->num;
+ if (vq->num - start < count)
+ n = vq->num - start;
+ else
+ n = count;
+ used = vq->used->ring + start;
+ if (copy_to_user(used, heads, sizeof(heads[0])*n)) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ if (n < count) { /* wrapped the ring */
+ used = vq->used->ring;
+ if (copy_to_user(used, heads+n, sizeof(heads[0])*(count-n))) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ }
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ if (put_user(vq->last_used_idx+count, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ smp_wmb();
/* Log used ring entry write. */
log_write(vq->log_base,
vq->log_addr + ((void *)used - (void *)vq->used),
@@ -1023,7 +1119,7 @@ int vhost_add_used(struct vhost_virtqueu
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
- vq->last_used_idx++;
+ vq->last_used_idx += count;
return 0;
}
@@ -1056,6 +1152,15 @@ void vhost_add_used_and_signal(struct vh
vhost_signal(dev, vq);
}
+/* multi-buffer version of vhost_add_used_and_signal */
+void vhost_add_used_and_signal_n(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads, int count)
+{
+ vhost_add_used_n(vq, heads, count);
+ vhost_signal(dev, vq);
+}
+
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_virtqueue *vq)
{
@@ -1080,7 +1185,7 @@ bool vhost_enable_notify(struct vhost_vi
return false;
}
- return avail_idx != vq->last_avail_idx;
+ return avail_idx != vq->avail_idx;
}
/* We don't need to be notified again. */
diff -ruNp net-next-p0/drivers/vhost/vhost.h net-next-v4/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/vhost.h 2010-04-19 14:15:24.000000000 -0700
@@ -84,7 +84,9 @@ struct vhost_virtqueue {
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t vhost_hlen;
+ size_t sock_hlen;
+ struct vring_used_elem heads[VHOST_NET_MAX_SG];
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
* flush the workqueue instead of synchronize_rcu. Therefore readers do
@@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
-unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num);
+unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard_desc(struct vhost_virtqueue *, int);
int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
- unsigned int head, int len);
+ unsigned int id, int len);
+void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
+ struct vring_used_elem *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
@@ -149,7 +158,8 @@ enum {
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: Michael S. Tsirkin @ 2010-04-22 17:43 UTC (permalink / raw)
To: David L Stevens; +Cc: kvm, virtualization
In-Reply-To: <1271715140.9755.14.camel@w-dls.beaverton.ibm.com>
On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> This patch adds the mergeable RX buffers feature to vhost.
>
> Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
BTW, which userspace should I use for testing this?
^ permalink raw reply
* Re: [PATCH v4] Add mergeable RX bufs support to vhost
From: Michael S. Tsirkin @ 2010-04-22 12:02 UTC (permalink / raw)
To: David L Stevens; +Cc: virtualization, kvm
In-Reply-To: <1271715140.9755.14.camel@w-dls.beaverton.ibm.com>
On Mon, Apr 19, 2010 at 03:12:19PM -0700, David L Stevens wrote:
> This patch adds the mergeable RX buffers feature to vhost.
>
> Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Looks pretty clean to me.
Could you send a checkpatch-clean version please?
We should also check performance implications.
Do you have any data?
Thanks!
> diff -ruNp net-next-p0/drivers/vhost/net.c net-next-v4/drivers/vhost/net.c
> --- net-next-p0/drivers/vhost/net.c 2010-03-22 12:04:38.000000000 -0700
> +++ net-next-v4/drivers/vhost/net.c 2010-04-19 14:23:38.000000000 -0700
> @@ -108,7 +108,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;
> @@ -127,13 +127,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);
> @@ -154,20 +154,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;
> }
> @@ -186,12 +186,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,
> @@ -202,14 +215,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;
> @@ -217,18 +230,18 @@ 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,
> + &in, vq_log, &log);
> + if (headcount < 0)
> + break;
> /* OK, now we need to know about added descriptors. */
> - if (head == vq->num) {
> + if (!headcount) {
> if (unlikely(vhost_enable_notify(vq))) {
> /* They have slipped one in as we were
> * doing that: check again. */
> @@ -240,46 +253,52 @@ static void handle_rx(struct vhost_net *
> break;
> }
> /* We don't need to be notified again. */
> - if (out) {
> - vq_err(vq, "Unexpected descriptor format for RX: "
> - "out %d, int %d\n",
> - out, in);
> - break;
> - }
> - /* Skip header. TODO: support TSO/mergeable rx buffers. */
> - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
> + /* Skip header. TODO: support TSO. */
> + s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
> msg.msg_iovlen = in;
> len = iov_length(vq->iov, in);
> /* Sanity check */
> if (!len) {
> vq_err(vq, "Unexpected header len for RX: "
> "%zd expected %zd\n",
> - iov_length(vq->hdr, s), hdr_size);
> + iov_length(vq->hdr, s), vhost_hlen);
> break;
> }
> err = sock->ops->recvmsg(NULL, sock, &msg,
> len, MSG_DONTWAIT | MSG_TRUNC);
> /* TODO: Check specific error and bomb out unless EAGAIN? */
> if (err < 0) {
> - vhost_discard_vq_desc(vq);
> + vhost_discard_desc(vq, headcount);
> break;
> }
> - /* TODO: Should check and handle checksum. */
> - if (err > len) {
> - pr_err("Discarded truncated rx packet: "
> - " len %d > %zd\n", err, len);
> - vhost_discard_vq_desc(vq);
> + if (err != datalen) {
> + pr_err("Discarded rx packet: "
> + " len %d, expected %zd\n", err, datalen);
> + vhost_discard_desc(vq, headcount);
> continue;
> }
> len = err;
> - err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
> + err = memcpy_toiovec(vq->hdr,(unsigned char *)&hdr, vhost_hlen);
> if (err) {
> vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
> vq->iov->iov_base, err);
> break;
> }
> - len += hdr_size;
> - vhost_add_used_and_signal(&net->dev, vq, head, len);
> + /* TODO: Should check and handle checksum. */
> + if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
> + struct virtio_net_hdr_mrg_rxbuf hdr;
> + struct iovec *iov = vhost_hlen ? vq->hdr : vq->iov;
> +
> + if (memcpy_toiovecend(iov, (unsigned char *)&headcount,
> + offsetof(typeof(hdr),num_buffers),
> + sizeof(hdr.num_buffers))) {
> + vq_err(vq, "Failed num_buffers write");
> + vhost_discard_desc(vq, headcount);
> + break;
> + }
> + }
> + len += vhost_hlen;
> + vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, headcount);
> if (unlikely(vq_log))
> vhost_log_write(vq, vq_log, log, len);
> total_len += len;
> @@ -560,9 +579,24 @@ done:
>
> static int vhost_net_set_features(struct vhost_net *n, u64 features)
> {
> - size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
> - sizeof(struct virtio_net_hdr) : 0;
> + size_t vhost_hlen;
> + size_t sock_hlen;
> int i;
> +
> + if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
> + /* vhost provides vnet_hdr */
> + vhost_hlen = sizeof(struct virtio_net_hdr);
> + if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
> + vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> + sock_hlen = 0;
> + } else {
> + /* socket provides vnet_hdr */
> + vhost_hlen = 0;
> + if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
> + sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
> + else
> + sock_hlen = sizeof(struct virtio_net_hdr);
> + }
> mutex_lock(&n->dev.mutex);
> if ((features & (1 << VHOST_F_LOG_ALL)) &&
> !vhost_log_access_ok(&n->dev)) {
> @@ -573,7 +607,8 @@ static int vhost_net_set_features(struct
> smp_wmb();
> for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
> mutex_lock(&n->vqs[i].mutex);
> - n->vqs[i].hdr_size = hdr_size;
> + n->vqs[i].vhost_hlen = vhost_hlen;
> + n->vqs[i].sock_hlen = sock_hlen;
> mutex_unlock(&n->vqs[i].mutex);
> }
> vhost_net_flush(n);
> diff -ruNp net-next-p0/drivers/vhost/vhost.c net-next-v4/drivers/vhost/vhost.c
> --- net-next-p0/drivers/vhost/vhost.c 2010-03-22 12:04:38.000000000 -0700
> +++ net-next-v4/drivers/vhost/vhost.c 2010-04-19 14:29:55.000000000 -0700
> @@ -113,7 +113,8 @@ static void vhost_vq_reset(struct vhost_
> vq->used_flags = 0;
> vq->log_used = false;
> vq->log_addr = -1ull;
> - vq->hdr_size = 0;
> + vq->vhost_hlen = 0;
> + vq->sock_hlen = 0;
> vq->private_data = NULL;
> vq->log_base = NULL;
> vq->error_ctx = NULL;
> @@ -856,6 +857,53 @@ static unsigned get_indirect(struct vhos
> return 0;
> }
>
> +/* This is a multi-buffer version of vhost_get_vq_desc
> + * @vq - the relevant virtqueue
> + * datalen - data length we'll be reading
> + * @iovcount - returned count of io vectors we fill
> + * @log - vhost log
> + * @log_num - log offset
> + * returns number of buffer heads allocated, negative on error
> + */
> +int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + int datalen, int *iovcount, struct vhost_log *log,
> + unsigned int *log_num)
> +{
> + int out, in;
> + int seg = 0; /* iov index */
> + int hc = 0; /* head count */
> + int rv;
> +
> + while (datalen > 0) {
> + if (hc >= VHOST_NET_MAX_SG) {
> + rv = -ENOBUFS;
> + goto err;
> + }
> + heads[hc].id = vhost_get_desc(vq->dev, vq, vq->iov+seg,
> + ARRAY_SIZE(vq->iov)-seg, &out,
> + &in, log, log_num);
> + if (heads[hc].id == vq->num) {
> + rv = 0;
> + goto err;
> + }
> + if (out || in <= 0) {
> + vq_err(vq, "unexpected descriptor format for RX: "
> + "out %d, in %d\n", out, in);
> + rv = -EINVAL;
> + goto err;
> + }
> + heads[hc].len = iov_length(vq->iov+seg, in);
> + datalen -= heads[hc].len;
> + hc++;
> + seg += in;
> + }
> + *iovcount = seg;
> + return hc;
> +err:
> + vhost_discard_desc(vq, hc);
> + return rv;
> +}
> +
> /* This looks in the virtqueue and for the first available buffer, and converts
> * it to an iovec for convenient access. Since descriptors consist of some
> * number of output then some number of input descriptors, it's actually two
> @@ -863,7 +911,7 @@ static unsigned get_indirect(struct vhos
> *
> * This function returns the descriptor number found, or vq->num (which
> * is never a valid descriptor number) if none was found. */
> -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> +unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> struct iovec iov[], unsigned int iov_size,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num)
> @@ -981,9 +1029,9 @@ unsigned vhost_get_vq_desc(struct vhost_
> }
>
> /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
> -void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
> +void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
> {
> - vq->last_avail_idx--;
> + vq->last_avail_idx -= n;
> }
>
> /* After we've used one of their buffers, we tell them about it. We'll then
> @@ -1012,6 +1060,54 @@ int vhost_add_used(struct vhost_virtqueu
> if (unlikely(vq->log_used)) {
> /* Make sure data is seen before log. */
> smp_wmb();
> + log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
> + (vq->last_used_idx % vq->num),
> + sizeof *vq->used->ring);
> + log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
> + if (vq->log_ctx)
> + eventfd_signal(vq->log_ctx, 1);
> + }
> + vq->last_used_idx++;
> + return 0;
> +}
> +
> +/* After we've used one of their buffers, we tell them about it. We'll then
> + * want to notify the guest, using eventfd. */
> +int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + int count)
> +{
> + struct vring_used_elem *used;
> + int start, n;
> +
> + if (count <= 0)
> + return -EINVAL;
> +
> + start = vq->last_used_idx % vq->num;
> + if (vq->num - start < count)
> + n = vq->num - start;
> + else
> + n = count;
> + used = vq->used->ring + start;
> + if (copy_to_user(used, heads, sizeof(heads[0])*n)) {
> + vq_err(vq, "Failed to write used");
> + return -EFAULT;
> + }
> + if (n < count) { /* wrapped the ring */
> + used = vq->used->ring;
> + if (copy_to_user(used, heads+n, sizeof(heads[0])*(count-n))) {
> + vq_err(vq, "Failed to write used");
> + return -EFAULT;
> + }
> + }
> + /* Make sure buffer is written before we update index. */
> + smp_wmb();
> + if (put_user(vq->last_used_idx+count, &vq->used->idx)) {
> + vq_err(vq, "Failed to increment used idx");
> + return -EFAULT;
> + }
> + if (unlikely(vq->log_used)) {
> + /* Make sure data is seen before log. */
> + smp_wmb();
> /* Log used ring entry write. */
> log_write(vq->log_base,
> vq->log_addr + ((void *)used - (void *)vq->used),
> @@ -1023,7 +1119,7 @@ int vhost_add_used(struct vhost_virtqueu
> if (vq->log_ctx)
> eventfd_signal(vq->log_ctx, 1);
> }
> - vq->last_used_idx++;
> + vq->last_used_idx += count;
> return 0;
> }
>
> @@ -1056,6 +1152,15 @@ void vhost_add_used_and_signal(struct vh
> vhost_signal(dev, vq);
> }
>
> +/* multi-buffer version of vhost_add_used_and_signal */
> +void vhost_add_used_and_signal_n(struct vhost_dev *dev,
> + struct vhost_virtqueue *vq,
> + struct vring_used_elem *heads, int count)
> +{
> + vhost_add_used_n(vq, heads, count);
> + vhost_signal(dev, vq);
> +}
> +
> /* OK, now we need to know about added descriptors. */
> bool vhost_enable_notify(struct vhost_virtqueue *vq)
> {
> @@ -1080,7 +1185,7 @@ bool vhost_enable_notify(struct vhost_vi
> return false;
> }
>
> - return avail_idx != vq->last_avail_idx;
> + return avail_idx != vq->avail_idx;
> }
>
> /* We don't need to be notified again. */
> diff -ruNp net-next-p0/drivers/vhost/vhost.h net-next-v4/drivers/vhost/vhost.h
> --- net-next-p0/drivers/vhost/vhost.h 2010-03-22 12:04:38.000000000 -0700
> +++ net-next-v4/drivers/vhost/vhost.h 2010-04-19 14:15:24.000000000 -0700
> @@ -84,7 +84,9 @@ struct vhost_virtqueue {
> struct iovec indirect[VHOST_NET_MAX_SG];
> struct iovec iov[VHOST_NET_MAX_SG];
> struct iovec hdr[VHOST_NET_MAX_SG];
> - size_t hdr_size;
> + size_t vhost_hlen;
> + size_t sock_hlen;
> + struct vring_used_elem heads[VHOST_NET_MAX_SG];
> /* We use a kind of RCU to access private pointer.
> * All readers access it from workqueue, which makes it possible to
> * flush the workqueue instead of synchronize_rcu. Therefore readers do
> @@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
> int vhost_vq_access_ok(struct vhost_virtqueue *vq);
> int vhost_log_access_ok(struct vhost_dev *);
>
> -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
> +int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + int datalen, int *iovcount, struct vhost_log *log,
> + unsigned int *log_num);
> +unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
> struct iovec iov[], unsigned int iov_count,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num);
> -void vhost_discard_vq_desc(struct vhost_virtqueue *);
> +void vhost_discard_desc(struct vhost_virtqueue *, int);
>
> int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
> -void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> +int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + int count);
> void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
> - unsigned int head, int len);
> + unsigned int id, int len);
> +void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
> + struct vring_used_elem *heads, int count);
> +void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> void vhost_disable_notify(struct vhost_virtqueue *);
> bool vhost_enable_notify(struct vhost_virtqueue *);
>
> @@ -149,7 +158,8 @@ enum {
> VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
> (1 << VIRTIO_RING_F_INDIRECT_DESC) |
> (1 << VHOST_F_LOG_ALL) |
> - (1 << VHOST_NET_F_VIRTIO_NET_HDR),
> + (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
> + (1 << VIRTIO_NET_F_MRG_RXBUF),
> };
>
> static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
>
>
> _______________________________________________
> Virtualization mailing list
> Virtualization@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* [PATCH] virtio: Fix GFP flags passed from the virtio balloon driver
From: Rusty Russell @ 2010-04-22 2:52 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-mm@kvack.org, virtualization, kvm, balbir
In-Reply-To: <20100421190704.GK3994@balbir.in.ibm.com>
From: Balbir Singh <balbir@linux.vnet.ibm.com>
The virtio balloon driver can dig into the reservation pools
of the OS to satisfy a balloon request. This is not advisable
and other balloon drivers (drivers/xen/balloon.c) avoid this
as well. The patch also adds changes to avoid printing a warning
if allocation fails, since we retry after sometime anyway.
Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: kvm <kvm@vger.kernel.org>
Cc: stable@kernel.org
---
drivers/virtio/virtio_balloon.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 369f2ee..f8ffe8c 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -102,7 +102,8 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
num = min(num, ARRAY_SIZE(vb->pfns));
for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
- struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
+ struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY |
+ __GFP_NOMEMALLOC | __GFP_NOWARN);
if (!page) {
if (printk_ratelimit())
dev_printk(KERN_INFO, &vb->vdev->dev,
^ permalink raw reply related
* Re: [Qemu-devel] [PATCH] virtio-spec: document block CMD and FLUSH
From: Michael S. Tsirkin @ 2010-04-21 10:39 UTC (permalink / raw)
To: Paul Brook; +Cc: kvm, Jamie Lokier, qemu-devel, virtualization, hch
In-Reply-To: <201004201422.58456.paul@codesourcery.com>
On Tue, Apr 20, 2010 at 02:22:58PM +0100, Paul Brook wrote:
> > Does this mean that virtio-blk supports all three combinations?
> >
> > 1. FLUSH that isn't a barrier
> > 2. FLUSH that is also a barrier
> > 3. Barrier that is not a flush
> >
> > 1 is good for fsync-like operations;
> > 2 is good for journalling-like ordered operations.
> > 3 sounds like it doesn't mean a lot as the host cache provides no
> > guarantees and has no ordering facility that can be used.
>
> (3) allows the guest to queue overlapping transfers with well defined results.
> I have no idea how useful this is in practice, but it's certainly plausible.
>
> Paul
In theory, yes.
At the moment, qemu only implements FLUSH and lguest only
implements barrier without FLUSH.
If you think it's useful, maybe start by using FLUSH+barrier
in linux guest driver, that'd demonstrate how it's used.
--
MST
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] virtio-spec: document block CMD and FLUSH
From: Paul Brook @ 2010-04-20 13:22 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm, Michael S. Tsirkin, Jamie Lokier, virtualization, hch
In-Reply-To: <20100420014635.GE21899@shareable.org>
> Does this mean that virtio-blk supports all three combinations?
>
> 1. FLUSH that isn't a barrier
> 2. FLUSH that is also a barrier
> 3. Barrier that is not a flush
>
> 1 is good for fsync-like operations;
> 2 is good for journalling-like ordered operations.
> 3 sounds like it doesn't mean a lot as the host cache provides no
> guarantees and has no ordering facility that can be used.
(3) allows the guest to queue overlapping transfers with well defined results.
I have no idea how useful this is in practice, but it's certainly plausible.
Paul
^ permalink raw reply
* Re: [PATCH] trans_virtio: use virtqueue_xxx wrappers
From: Rusty Russell @ 2010-04-20 9:10 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: virtualization
In-Reply-To: <20100413131150.GA25652@redhat.com>
On Tue, 13 Apr 2010 10:41:50 pm Michael S. Tsirkin wrote:
> Switch trans_virtio to new virtqueue_xxx wrappers.
Thanks, I've applied all these.
Cheers,
Rusty.
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] virtio-spec: document block CMD and FLUSH
From: Jamie Lokier @ 2010-04-20 1:46 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: virtualization, hch, kvm, qemu-devel
In-Reply-To: <20100218222220.GA14847@redhat.com>
Michael S. Tsirkin wrote:
> I took a stub at documenting CMD and FLUSH request types in virtio
> block. Christoph, could you look over this please?
>
> I note that the interface seems full of warts to me,
> this might be a first step to cleaning them.
>
> One issue I struggled with especially is how type
> field mixes bits and non-bit values. I ended up
> simply defining all legal values, so that we have
> CMD = 2, CMD_OUT = 3 and so on.
>
> I also avoided instroducing inhdr/outhdr structures
> that virtio blk driver in linux uses, I was concerned
> that nesting tables will confuse the reader.
>
> Comments welcome.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> --
>
> diff --git a/virtio-spec.lyx b/virtio-spec.lyx
> index d16104a..ed35893 100644
> --- a/virtio-spec.lyx
> +++ b/virtio-spec.lyx
> @@ -67,7 +67,11 @@ IBM Corporation
> \end_layout
>
> \begin_layout Standard
> +
> +\change_deleted 0 1266531118
> FIXME: virtio block scsi passthrough section
> +\change_unchanged
> +
> \end_layout
>
> \begin_layout Standard
> @@ -4376,7 +4380,7 @@ struct virtio_net_ctrl_mac {
> The device can filter incoming packets by any number of destination MAC
> addresses.
> \begin_inset Foot
> -status open
> +status collapsed
>
> \begin_layout Plain Layout
> Since there are no guarentees, it can use a hash filter orsilently switch
> @@ -4549,6 +4553,22 @@ blk_size
> \end_inset
>
> .
> +\change_inserted 0 1266444580
> +
> +\end_layout
> +
> +\begin_layout Description
> +
> +\change_inserted 0 1266471229
> +VIRTIO_BLK_F_SCSI (7) Device supports scsi packet commands.
> +\end_layout
> +
> +\begin_layout Description
> +
> +\change_inserted 0 1266444605
> +VIRTIO_BLK_F_FLUSH (9) Cache flush command support.
> +\change_unchanged
> +
> \end_layout
>
> \begin_layout Description
> @@ -4700,17 +4720,25 @@ struct virtio_blk_req {
>
> \begin_layout Plain Layout
>
> +\change_deleted 0 1266472188
> +
> #define VIRTIO_BLK_T_IN 0
> \end_layout
>
> \begin_layout Plain Layout
>
> +\change_deleted 0 1266472188
> +
> #define VIRTIO_BLK_T_OUT 1
> \end_layout
>
> \begin_layout Plain Layout
>
> +\change_deleted 0 1266472188
> +
> #define VIRTIO_BLK_T_BARRIER 0x80000000
> +\change_unchanged
> +
> \end_layout
>
> \begin_layout Plain Layout
> @@ -4735,11 +4763,15 @@ struct virtio_blk_req {
>
> \begin_layout Plain Layout
>
> +\change_deleted 0 1266472204
> +
> #define VIRTIO_BLK_S_OK 0
> \end_layout
>
> \begin_layout Plain Layout
>
> +\change_deleted 0 1266472204
> +
> #define VIRTIO_BLK_S_IOERR 1
> \end_layout
>
> @@ -4759,32 +4791,481 @@ struct virtio_blk_req {
> \end_layout
>
> \begin_layout Standard
> -The type of the request is either a read (VIRTIO_BLK_T_IN) or a write (VIRTIO_BL
> -K_T_OUT); the high bit indicates that this request acts as a barrier and
> - that all preceeding requests must be complete before this one, and all
> - following requests must not be started until this is complete.
> +
> +\change_inserted 0 1266472490
> +If the device has VIRTIO_BLK_F_SCSI feature, it can also support scsi packet
> + command requests, each of these requests is of form:
> +\begin_inset listings
> +inline false
> +status open
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472395
> +
> +struct virtio_scsi_pc_req {
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472375
> +
> + u32 type;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472375
> +
> + u32 ioprio;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266474298
> +
> + u64 sector;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266474308
> +
> + char cmd[];
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266505809
> +
> + char data[][512];
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266505825
> +
> +#define SCSI_SENSE_BUFFERSIZE 96
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266505848
> +
> + u8 sense[SCSI_SENSE_BUFFERSIZE];
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472969
> +
> + u32 errors;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472979
> +
> + u32 data_len;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472984
> +
> + u32 sense_len;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472987
> +
> + u32 residual;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472375
> +
> + u8 status;
> +\end_layout
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266472375
> +
> +};
> +\end_layout
> +
> +\end_inset
> +
> +
> +\change_unchanged
> +
> \end_layout
>
> \begin_layout Standard
> -The ioprio field is a hint about the relative priorities of requests to
> - the device: higher numbers indicate more important requests.
> +The
> +\emph on
> +type
> +\emph default
> + of the request is either a read (VIRTIO_BLK_T_IN)
> +\change_inserted 0 1266495815
> +,
> +\change_unchanged
> +
> +\change_deleted 0 1266495817
> +or
> +\change_unchanged
> + a write (VIRTIO_BLK_T_OUT)
> +\change_inserted 0 1266497316
> +, a scsi packet command (VIRTIO_BLK_T_SCSI_CMD or VIRTIO_BLK_T_SCSI_CMD_OUT
> +\begin_inset Foot
> +status open
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266497390
> +the SCSI_CMD and SCSI_CMD_OUT types are equivalent, the device does not
> + distinguish between them
> +\change_unchanged
> +
> +\end_layout
> +
> +\end_inset
> +
> +) or a flush (VIRTIO_BLK_T_FLUSH or VIRTIO_BLK_T_FLUSH_OUT
> +\begin_inset Foot
> +status open
> +
> +\begin_layout Plain Layout
> +
> +\change_inserted 0 1266497402
> +the FLUSH and FLUSH_OUT types are equivalent, the device does not distinguish
> + between them
> +\change_unchanged
> +
> +\end_layout
> +
> +\end_inset
> +
> +)
> +\change_deleted 0 1266503753
> +;
> +\change_inserted 0 1266503758
> +.
> +
> +\change_unchanged
> +
> +\change_inserted 0 1266497301
> +If the device has VIRTIO_BLK_F_BARRIER feature
> +\begin_inset space ~
> +\end_inset
> +
> +
> +\change_unchanged
> +the high bit
> +\change_inserted 0 1266497301
> + (VIRTIO_BLK_T_BARRIER)
> +\change_unchanged
> + indicates that this request acts as a barrier and that all preceeding requests
> + must be complete before this one, and all following requests must not be
> + started until this is complete.
> +
> +\change_inserted 0 1266504385
> + Note that a barrier does not flush caches in the underlying backend device
> + in host, and thus does not serve as data consistency guarantee.
> + Driver must use FLUSH request to flush the host cache.
> +\change_unchanged
> +
Does this mean that virtio-blk supports all three combinations?
1. FLUSH that isn't a barrier
2. FLUSH that is also a barrier
3. Barrier that is not a flush
1 is good for fsync-like operations;
2 is good for journalling-like ordered operations.
3 sounds like it doesn't mean a lot as the host cache provides no
guarantees and has no ordering facility that can be used.
-- Jamie
^ permalink raw reply
* [PATCH v4] Add mergeable RX bufs support to vhost
From: David L Stevens @ 2010-04-19 22:12 UTC (permalink / raw)
To: mst; +Cc: kvm, virtualization
This patch adds the mergeable RX buffers feature to vhost.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
diff -ruNp net-next-p0/drivers/vhost/net.c net-next-v4/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/net.c 2010-04-19 14:23:38.000000000 -0700
@@ -108,7 +108,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;
@@ -127,13 +127,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);
@@ -154,20 +154,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;
}
@@ -186,12 +186,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,
@@ -202,14 +215,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;
@@ -217,18 +230,18 @@ 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,
+ &in, vq_log, &log);
+ if (headcount < 0)
+ break;
/* OK, now we need to know about added descriptors. */
- if (head == vq->num) {
+ if (!headcount) {
if (unlikely(vhost_enable_notify(vq))) {
/* They have slipped one in as we were
* doing that: check again. */
@@ -240,46 +253,52 @@ static void handle_rx(struct vhost_net *
break;
}
/* We don't need to be notified again. */
- if (out) {
- vq_err(vq, "Unexpected descriptor format for RX: "
- "out %d, int %d\n",
- out, in);
- break;
- }
- /* Skip header. TODO: support TSO/mergeable rx buffers. */
- s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+ /* Skip header. TODO: support TSO. */
+ s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
msg.msg_iovlen = in;
len = iov_length(vq->iov, in);
/* Sanity check */
if (!len) {
vq_err(vq, "Unexpected header len for RX: "
"%zd expected %zd\n",
- iov_length(vq->hdr, s), hdr_size);
+ iov_length(vq->hdr, s), vhost_hlen);
break;
}
err = sock->ops->recvmsg(NULL, sock, &msg,
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard_desc(vq, headcount);
break;
}
- /* TODO: Should check and handle checksum. */
- if (err > len) {
- pr_err("Discarded truncated rx packet: "
- " len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ if (err != datalen) {
+ pr_err("Discarded rx packet: "
+ " len %d, expected %zd\n", err, datalen);
+ vhost_discard_desc(vq, headcount);
continue;
}
len = err;
- err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+ err = memcpy_toiovec(vq->hdr,(unsigned char *)&hdr, vhost_hlen);
if (err) {
vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
vq->iov->iov_base, err);
break;
}
- len += hdr_size;
- vhost_add_used_and_signal(&net->dev, vq, head, len);
+ /* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
+ struct virtio_net_hdr_mrg_rxbuf hdr;
+ struct iovec *iov = vhost_hlen ? vq->hdr : vq->iov;
+
+ if (memcpy_toiovecend(iov, (unsigned char *)&headcount,
+ offsetof(typeof(hdr),num_buffers),
+ sizeof(hdr.num_buffers))) {
+ vq_err(vq, "Failed num_buffers write");
+ vhost_discard_desc(vq, headcount);
+ break;
+ }
+ }
+ len += vhost_hlen;
+ vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, headcount);
if (unlikely(vq_log))
vhost_log_write(vq, vq_log, log, len);
total_len += len;
@@ -560,9 +579,24 @@ done:
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
+ size_t vhost_hlen;
+ size_t sock_hlen;
int i;
+
+ if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
+ /* vhost provides vnet_hdr */
+ vhost_hlen = sizeof(struct virtio_net_hdr);
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ sock_hlen = 0;
+ } else {
+ /* socket provides vnet_hdr */
+ vhost_hlen = 0;
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+ sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ sock_hlen = sizeof(struct virtio_net_hdr);
+ }
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
!vhost_log_access_ok(&n->dev)) {
@@ -573,7 +607,8 @@ static int vhost_net_set_features(struct
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ n->vqs[i].vhost_hlen = vhost_hlen;
+ n->vqs[i].sock_hlen = sock_hlen;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
diff -ruNp net-next-p0/drivers/vhost/vhost.c net-next-v4/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/vhost.c 2010-04-19 14:29:55.000000000 -0700
@@ -113,7 +113,8 @@ static void vhost_vq_reset(struct vhost_
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->vhost_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -856,6 +857,53 @@ static unsigned get_indirect(struct vhos
return 0;
}
+/* This is a multi-buffer version of vhost_get_vq_desc
+ * @vq - the relevant virtqueue
+ * datalen - data length we'll be reading
+ * @iovcount - returned count of io vectors we fill
+ * @log - vhost log
+ * @log_num - log offset
+ * returns number of buffer heads allocated, negative on error
+ */
+int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num)
+{
+ int out, in;
+ int seg = 0; /* iov index */
+ int hc = 0; /* head count */
+ int rv;
+
+ while (datalen > 0) {
+ if (hc >= VHOST_NET_MAX_SG) {
+ rv = -ENOBUFS;
+ goto err;
+ }
+ heads[hc].id = vhost_get_desc(vq->dev, vq, vq->iov+seg,
+ ARRAY_SIZE(vq->iov)-seg, &out,
+ &in, log, log_num);
+ if (heads[hc].id == vq->num) {
+ rv = 0;
+ goto err;
+ }
+ if (out || in <= 0) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ rv = -EINVAL;
+ goto err;
+ }
+ heads[hc].len = iov_length(vq->iov+seg, in);
+ datalen -= heads[hc].len;
+ hc++;
+ seg += in;
+ }
+ *iovcount = seg;
+ return hc;
+err:
+ vhost_discard_desc(vq, hc);
+ return rv;
+}
+
/* This looks in the virtqueue and for the first available buffer, and converts
* it to an iovec for convenient access. Since descriptors consist of some
* number of output then some number of input descriptors, it's actually two
@@ -863,7 +911,7 @@ static unsigned get_indirect(struct vhos
*
* This function returns the descriptor number found, or vq->num (which
* is never a valid descriptor number) if none was found. */
-unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
struct iovec iov[], unsigned int iov_size,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num)
@@ -981,9 +1029,9 @@ unsigned vhost_get_vq_desc(struct vhost_
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll then
@@ -1012,6 +1060,54 @@ int vhost_add_used(struct vhost_virtqueu
if (unlikely(vq->log_used)) {
/* Make sure data is seen before log. */
smp_wmb();
+ log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+ (vq->last_used_idx % vq->num),
+ sizeof *vq->used->ring);
+ log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ vq->last_used_idx++;
+ return 0;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ int count)
+{
+ struct vring_used_elem *used;
+ int start, n;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ start = vq->last_used_idx % vq->num;
+ if (vq->num - start < count)
+ n = vq->num - start;
+ else
+ n = count;
+ used = vq->used->ring + start;
+ if (copy_to_user(used, heads, sizeof(heads[0])*n)) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ if (n < count) { /* wrapped the ring */
+ used = vq->used->ring;
+ if (copy_to_user(used, heads+n, sizeof(heads[0])*(count-n))) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ }
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ if (put_user(vq->last_used_idx+count, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ smp_wmb();
/* Log used ring entry write. */
log_write(vq->log_base,
vq->log_addr + ((void *)used - (void *)vq->used),
@@ -1023,7 +1119,7 @@ int vhost_add_used(struct vhost_virtqueu
if (vq->log_ctx)
eventfd_signal(vq->log_ctx, 1);
}
- vq->last_used_idx++;
+ vq->last_used_idx += count;
return 0;
}
@@ -1056,6 +1152,15 @@ void vhost_add_used_and_signal(struct vh
vhost_signal(dev, vq);
}
+/* multi-buffer version of vhost_add_used_and_signal */
+void vhost_add_used_and_signal_n(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads, int count)
+{
+ vhost_add_used_n(vq, heads, count);
+ vhost_signal(dev, vq);
+}
+
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_virtqueue *vq)
{
@@ -1080,7 +1185,7 @@ bool vhost_enable_notify(struct vhost_vi
return false;
}
- return avail_idx != vq->last_avail_idx;
+ return avail_idx != vq->avail_idx;
}
/* We don't need to be notified again. */
diff -ruNp net-next-p0/drivers/vhost/vhost.h net-next-v4/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h 2010-03-22 12:04:38.000000000 -0700
+++ net-next-v4/drivers/vhost/vhost.h 2010-04-19 14:15:24.000000000 -0700
@@ -84,7 +84,9 @@ struct vhost_virtqueue {
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t vhost_hlen;
+ size_t sock_hlen;
+ struct vring_used_elem heads[VHOST_NET_MAX_SG];
/* We use a kind of RCU to access private pointer.
* All readers access it from workqueue, which makes it possible to
* flush the workqueue instead of synchronize_rcu. Therefore readers do
@@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
-unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int datalen, int *iovcount, struct vhost_log *log,
+ unsigned int *log_num);
+unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard_desc(struct vhost_virtqueue *, int);
int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ int count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
- unsigned int head, int len);
+ unsigned int id, int len);
+void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
+ struct vring_used_elem *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
@@ -149,7 +158,8 @@ enum {
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Michael S. Tsirkin @ 2010-04-19 21:26 UTC (permalink / raw)
To: Rusty Russell; +Cc: kvm, hch, qemu-devel, Anthony Liguori, virtualization
In-Reply-To: <20100218222220.GA14847@redhat.com>
On Fri, Feb 19, 2010 at 12:22:20AM +0200, Michael S. Tsirkin wrote:
> I took a stub at documenting CMD and FLUSH request types in virtio
> block.
Any comments?
^ permalink raw reply
* KVM Forum 2010: Call for Papers
From: KVM Forum 2010 Program Committee @ 2010-04-19 21:19 UTC (permalink / raw)
To: virtualization
=================================================================
CALL FOR PAPERS
KVM Forum 2010
=================================================================
DESCRIPTION
The KVM Forum is back! After a break last year we're proud to present
this year's gathering around KVM again. The idea is to have everyone
involved with KVM development come together to talk about the future
and current state of KVM, teaching everyone some pieces of the puzzle
they might be missing without.
So if you're a KVM developer, mark the dates in your calendar! If
possible, also submit a talk -- we're interested in a wide variety of
KVM topics, so don't hesitate to propose a talk on your work.
If you're not a KVM developer, please read on nevertheless (or jump to
END USER COLLABORATION).
DATES / LOCATION
Conference: August 9 - 10, 2010
Location: Renaissance Boston Waterfront in Boston, MA
Abstracts due: May 14th, 2010
Notification: May 28th, 2010
Yes, we're colocated with LinuxCon. Tickets for the KVM Forum also count
for LinuxCon.
http://events.linuxfoundation.org/component/registrationpro/?func=details&did=34
PROCESS
At first check if it's before May 14th. If you're past that date, you're
out of luck. Now try to think hard and come up with a great idea that
you could talk about. Once you have that set, we need you to write up
a short abstract (~150 words) on it. In your submission please note
how long your talk will take. Slots vary in length up to one hour.
Also include in your proposal the proposal type -- one of: technical talk,
breakout session, or end-user talk. Add that information to the abstract
and submit it at the following URL:
http://events.linuxfoundation.org/cfp/cfp-add
Now, wait until May 24th. You will receive a notification on whether
your talk was accepted or not.
SCOPE OF TALKS
We have a list of suggested presentation topics below. These suggestions
are just for guidance, please feel free to submit a proposal on any
of these or related topics. In general, the more it's about backend
infrastructure, the better.
KVM
- Scaling and performance
- Nested virtualization
- I/O improvements
- Driver domains
- Time keeping
- Memory management (page sharing, swapping, huge pages, etc)
- Fault tolerance
- VEPA, vswitch
Embedded KVM
- KVM on ARM, PPC, MIPS, ...?
- Real-time requirements host/guest
- Device pass-through w/o iommu
- Custom device/platform models
QEMU
- Device model improvements
- New devices
- Security model
- Scaling and performance
- Desktop virtualization
- Increasing robustness
- Management interfaces
- QMP protocol and implementation
- Live migration
Virtio
- Speeding up existing devices
- Vhost
- Alternatives
- Using virtio in non-kvm environments
- Virtio on non-Linux
Management infrastructure
- Libvirt
- Kvm autotest
- Easy networking
- Qemud
BREAKOUT SESSION
We will reserve some time each day to break out for working sessions.
These sessions will be less formal than a presentation and more focused
on developing a solution to some real development issue. If you are
interested in getting developers together to hack on some code, submit
your proposal and just make it clear it's a breakout session proposal.
END-USER COLLABORATION
One of the big challenges as developers is to know what, where and how
people actually use our software. To solve this issue at least a little,
there will be a few slots reserved for end users talking about their
deployments, problems and achievements.
So if you have a KVM based deployment running in production or are about
to roll out one, please also submit a talk (see PROCESS), and simply
mark it asn an end-user collaboration proposal. We would love to have
an open discussion of fields where KVM/Qemu can still improve and you
would have the unique chance to steer that process!
Keep in mind that most of the Forum will be focused on development though,
so we suggest you also come with a good portion of technical interest :-).
And of course, no product marketing please! The purpose is to engage
with KVM developers.
LIGHTNING TALKS
In addition to submitted talks we will also have some room for lightning
talks. So if you have something you think might be done until the KVM
Forum, but you're not sure you could fill 15 minutes with it. Or if you
don't know if you'll make it until there, just keep in mind that you
will still get the chance to talk about it. Lightning talk submissions
and scheduling will be handled on-site at KVM Forum.
Thank you for your interest in KVM. We're looking forward to your
submissions and seeing you at the KVM Forum 2010 in August! Now, start
thinking about that talk you want to give.
Thanks,
your KVM Forum 2010 Program Commitee
Alexander Graf, Novell
Anthony Liguori, IBM
Avi Kivity, Red Hat
Chris Wright, Red Hat
Dor Laor, Red Hat
Jan Kiszka, Siemens
Please contact us with any questions or comments.
KVM-Forum-2010-PC@redhat.com
^ permalink raw reply
* Re: [PATCH 0/6] virtio: virtqueue ops cleanup
From: Michael S. Tsirkin @ 2010-04-19 20:49 UTC (permalink / raw)
To: rusty, virtualization
In-Reply-To: <cover.1271078235.git.mst@redhat.com>
On Mon, Apr 12, 2010 at 04:18:19PM +0300, Michael S. Tsirkin wrote:
> This patchset does the following:
> - add inline wrappers converting the above to virtqueue_kick(dev->vq)
> - convert all users to this API
> - remove vq_ops indirection, implementing virtqueue_xx directly
> in virtio_ring
Ping.
what's the thinking on this patchset?
The reason I want it in now is because I have
several improvements for the APIs in mind,
and with less layers it's much easier to
extend things.
--
MST
^ permalink raw reply
* [PATCH 1/1] Staging: hv: Fix a bug affecting IPv6
From: Haiyang Zhang @ 2010-04-19 15:32 UTC (permalink / raw)
To: Greg KH, 'linux-kernel@vger.kernel.org',
devel@driverdev.osuosl.org, virtualiz
Cc: Toshikazu Sakai
From: Haiyang Zhang <haiyangz@microsoft.com>
Fix a bug affecting IPv6
Added the multicast flag for proper IPv6 function.
Credits go to Toshikazu Sakai <toshikas@microsoft.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Toshikazu Sakai <toshikas@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/staging/hv/RndisFilter.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/RndisFilter.c
index cd2930d..6704f64 100644
--- a/drivers/staging/hv/RndisFilter.c
+++ b/drivers/staging/hv/RndisFilter.c
@@ -751,6 +751,7 @@ static int RndisFilterOpenDevice(struct rndis_device *Device)
ret = RndisFilterSetPacketFilter(Device,
NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
if (ret == 0)
Device->State = RNDIS_DEV_DATAINITIALIZED;
--
1.6.3.2
^ permalink raw reply related
* HPDC 2010: Call for Participation
From: Peter Dinda @ 2010-04-18 23:09 UTC (permalink / raw)
To: tcpp-announce, performance, infodir_SIGARCH, sigplan-l, publicity,
micro_publicity, hpc-announc
CALL FOR PARTICIPATION
ACM HPDC 2010 - hpdc.org
19th ACM International Symposium on
High Performance Distributed Systems
Chicago, Illinois, USA
June 20-25, 2010
Overview
The ACM International Symposium on High Performance Distributed
Computing (HPDC) is the premier venue for presenting the latest
research on the design, implementation, evaluation, and use of
parallel and distributed systems for high performance and high end
computing. The 19th installment of HPDC will take place in the heart
of Chicago, Illinois, the third largest city in the United States and
a major technological and cultural capital located on the shore of
Lake Michigan, one of the largest freshwater lakes in the world.
Highlights
* 3 Keynotes: Guy Steele (Sun/Oracle), Randal Bryant (CMU), 3rd TBA
* Single track presentation of 23 full papers (25% acceptance rate)
and 22 posters
Workflows, Resources and Clouds, Map Reduce and Debugging, Data
Centers and Virtualization, Storage and I/O, Applications and
Provenance, Communication and Scheduling, Best Papers
* Panel on expanding parallel programming beyond the usual suspects
* Industry session
(email hpdc2010-industry-session@presciencelab.org for participation)
* Wild and crazy ideas session
(email hpdc2010-wild@presciencelab.org for participation)
* 8 co-located workshops
Emerging Computational Methods for the Life Sciences, LSAP:
Large-Scale System and Application Performance, MDQCS: Managing
Data Quality for Collaborative Science, ScienceCloud: Workshop on
Scientific Cloud Computing, CLADE: Challenges of Large
Applications in Distributed Environments, DIDC: Data Intensive
Distributed Computing, MAPREDUCE: Map Reduce and its Applications,
VTDC: Virtualization Technologies for Distributed Computing
* Co-located Open Grid Forum meeting (OGF29)
* Full program available from web site (hpdc.org)
Venue, Registration, Student Travel Grants, and Sponsorship
All events will take place at the Doubletree Hotel Chicago Magnificent
Mile, located within easy walking distance of numerous downtown
Chicago attractions and Lake Michigan (including beaches), with easy
access to the entire Chicago area via subway.
Discounted registration is available through May 31. A discounted
room rate is available through May 21. Student travel grant
applications are being accepted. For more information and to
register, please visit hpdc.org.
HPDC is pleased to acknowledge support or sponsorship from ACM, NSF,
Intel, Google, NVIDIA, the Computation Institute at the University of
Chicago, the Autonomic Computing Lab at the University of Arizona, and
the Department of Electrical Engineering and Computer Science at
Northwestern University.
^ permalink raw reply
* Update virtio spec with new virtio console ABI information
From: Amit Shah @ 2010-04-16 7:14 UTC (permalink / raw)
To: Rusty Russell; +Cc: Virtualization List
Hello Rusty,
This patch updates the virtio spec (0.8.6) with the new ABI information
for virtio-console.
Please apply.
--- virtio-spec-0.8.6.lyx 2010-04-16 12:06:13.416075709 +0530
+++ virtio-spec-0.8.6-virtio-console.lyx 2010-04-16 12:41:54.656201703 +0530
@@ -36,7 +36,7 @@
\paperpagestyle default
\tracking_changes true
\output_changes false
-\author ""
+\author "Amit Shah"
\author ""
\end_header
@@ -4676,7 +4676,20 @@
The control virtqueues are used to communicate information between the
device and the driver about ports being opened and closed on either side
of the connection, indication from the host about whether a particular
- port is a console port, port hotunplug, etc.
+ port is a console port,
+\change_inserted 0 1271399891
+adding new ports,
+\change_unchanged
+port hot
+\change_inserted 0 1271399887
+-plug/
+\change_unchanged
+unplug, etc.
+\change_inserted 0 1271399946
+, and indication from the guest about whether a port or a device was successfull
+y added, port open/close, etc..
+
+\change_unchanged
For data IO, one or more empty buffers are placed in the receive queue
for incoming data and outgoing characters are placed in the transmit queue.
\end_layout
@@ -4739,8 +4752,11 @@
layout The size of the console is supplied in the configuration space if
the VIRTIO_CONSOLE_F_SIZE feature is set.
Furthermore, if the VIRTIO_CONSOLE_F_MULTIPORT feature is set, the maximum
- number of ports supported by the device and the number of ports currently
- active can be fetched.
+ number of ports supported by the device
+\change_deleted 0 1271400029
+ and the number of ports currently active
+\change_unchanged
+ can be fetched.
\begin_inset listings
inline false
status open
@@ -4767,11 +4783,17 @@
\begin_layout Plain Layout
u32 max_nr_ports;
+\change_deleted 0 1271399998
+
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271399993
+
u32 nr_ports;
+\change_unchanged
+
\end_layout
\begin_layout Plain Layout
@@ -4797,12 +4819,30 @@
If the VIRTIO_CONSOLE_F_MULTIPORT feature is negotiated, the driver can
spawn multiple ports, not all of which may be attached to a console.
Some could be generic ports.
- In this case, the control virtqueues are enabled and according to the nr_ports
- configuration-space value, the appropriate number of ports and corresponding
- virtqueues are spawned.
- After creating and initializing each port, a VIRTIO_CONSOLE_PORT_READY
- control message is sent to the host for that port so the host can let us
- know of any additional configuration options set for that port.
+ In this case, the control virtqueues are enabled and according to the
+\change_inserted 0 1271400055
+max_
+\change_unchanged
+nr_ports configuration-space value, the appropriate number of
+\change_deleted 0 1271400070
+ports and corresponding
+\change_unchanged
+virtqueues are
+\change_deleted 0 1271400075
+spawned
+\change_inserted 0 1271400076
+created
+\change_unchanged
+.
+
+\change_inserted 0 1271400112
+A control message indicating the driver is ready is sent to the host.
+ The host can then send control messages for adding new ports to the device.
+
+\change_unchanged
+After creating and initializing each port, a VIRTIO_CONSOLE_PORT_READY control
+ message is sent to the host for that port so the host can let us know of
+ any additional configuration options set for that port.
\end_layout
\begin_layout Enumerate
@@ -4822,6 +4862,13 @@
Because this is high importance and low bandwidth, the current Linux implementat
ion polls for the buffer to be used, rather than waiting for an interrupt,
simplifying the implementation significantly.
+
+\change_inserted 0 1271400345
+ However, for generic serial ports with the O_NONBLOCK flag set, the polling
+ limitation is relaxed and the consumed buffers are freed upon the next
+ write or poll call or when a port is closed or hot-unplugged.
+\change_unchanged
+
\end_layout
\end_inset
@@ -4839,12 +4886,32 @@
If the driver negotiated the VIRTIO_CONSOLE_F_SIZE feature, a configuration
change interrupt may occur.
The updated size can be read from the configuration fields.
-\end_layout
-
-\begin_layout Enumerate
+\change_deleted 0 1271400359
If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT feature, a configuration
change interrupt may occur that bumps up the value of nr_ports.
In this case, ports are hot-added.
+\change_inserted 0 1271400879
+
+\end_layout
+
+\begin_layout Enumerate
+
+\change_inserted 0 1271401808
+If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT feature, active
+ ports are announced by the host using the VIRTIO_CONSOLE_PORT_ADD control
+ message.
+ The same message is used for port hot-plug as well.
+\end_layout
+
+\begin_layout Enumerate
+
+\change_inserted 0 1271401905
+If the host specified a port 'name', a sysfs attribute is created with the
+ name filled in, so that udev rules can be written that can create a symlink
+ from the port's name to the char device for port discovery by applications
+ in the guest.
+\change_unchanged
+
\end_layout
\begin_layout Enumerate
@@ -4892,32 +4959,102 @@
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_PORT_READY 0
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_CONSOLE_PORT 1
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_RESIZE 2
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_PORT_OPEN 3
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_PORT_NAME 4
\end_layout
\begin_layout Plain Layout
+\change_deleted 0 1271400377
+
#define VIRTIO_CONSOLE_PORT_REMOVE 5
+\change_inserted 0 1271400378
+
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400814
+
+#define VIRTIO_CONSOLE_DEVICE_READY 0
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400820
+
+#define VIRTIO_CONSOLE_PORT_ADD 1
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400823
+
+#define VIRTIO_CONSOLE_PORT_REMOVE 2
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400827
+
+#define VIRTIO_CONSOLE_PORT_READY 3
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400830
+
+#define VIRTIO_CONSOLE_CONSOLE_PORT 4
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400835
+
+#define VIRTIO_CONSOLE_RESIZE 5
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400839
+
+#define VIRTIO_CONSOLE_PORT_OPEN 6
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1271400842
+
+#define VIRTIO_CONSOLE_PORT_NAME 7
\end_layout
\end_inset
^ permalink raw reply
* Re: A clocksource driver for HyperV
From: Ky Srinivasan @ 2010-04-15 20:04 UTC (permalink / raw)
To: devel, Virtualization; +Cc: haiyangz, gregkh
In-Reply-To: <4BBCDF93.9010305@goop.org>
[-- Attachment #1: Type: text/plain, Size: 305 bytes --]
Jeremy,
As suggested by you, I am enclosing a patch that integrates HyperV detection with the current hypervisor detection mechanism in the kernel. Also attached is a HyperV clocksource patch that uses this new functionality.
Signed-off-by: K. Y. Srinivasan <ksrinivasan@novell.com>
[-- Attachment #2: hyperv_detection.patch --]
[-- Type: text/plain, Size: 7013 bytes --]
From: K. Y. Srinivasan <ksrinivasan@novell.com>
Subject: HyperV Detection code.
References: None
Patch-mainline:
This patch integrates HyperV detection within the framework currently used by
VmWare. With this patch, we can avoid having to replicate the HyperV detection
code in each of the HyperV specific Linux drivers - MSFT Linux Integration
Components.
Signed-off-by: K. Y. Srinivasan <ksrinivasan@novell.com>
Index: linux-2.6.34-rc4/arch/x86/include/asm/processor.h
===================================================================
--- linux-2.6.34-rc4.orig/arch/x86/include/asm/processor.h 2010-04-12 19:41:35.000000000 -0600
+++ linux-2.6.34-rc4/arch/x86/include/asm/processor.h 2010-04-15 10:00:18.000000000 -0600
@@ -114,6 +114,8 @@ struct cpuinfo_x86 {
u16 cpu_index;
#endif
unsigned int x86_hyper_vendor;
+ /* The layout of this field is hypervisor specific */
+ unsigned int x86_hyper_features;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define X86_VENDOR_INTEL 0
@@ -129,6 +131,7 @@ struct cpuinfo_x86 {
#define X86_HYPER_VENDOR_NONE 0
#define X86_HYPER_VENDOR_VMWARE 1
+#define X86_HYPER_VENDOR_MSFT 2
/*
* capabilities of CPUs
Index: linux-2.6.34-rc4/arch/x86/kernel/cpu/Makefile
===================================================================
--- linux-2.6.34-rc4.orig/arch/x86/kernel/cpu/Makefile 2010-04-12 19:41:35.000000000 -0600
+++ linux-2.6.34-rc4/arch/x86/kernel/cpu/Makefile 2010-04-15 10:00:18.000000000 -0600
@@ -14,7 +14,7 @@ CFLAGS_common.o := $(nostackp)
obj-y := intel_cacheinfo.o addon_cpuid_features.o
obj-y += proc.o capflags.o powerflags.o common.o
-obj-y += vmware.o hypervisor.o sched.o
+obj-y += vmware.o hypervisor.o sched.o hyperv.o
obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o
obj-$(CONFIG_X86_64) += bugs_64.o
Index: linux-2.6.34-rc4/arch/x86/kernel/cpu/hyperv.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.34-rc4/arch/x86/kernel/cpu/hyperv.c 2010-04-15 10:00:18.000000000 -0600
@@ -0,0 +1,66 @@
+/*
+ * HyperV Detection code.
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/processor.h>
+#include <asm/hyperv.h>
+
+
+int hyperv_platform(void)
+{
+ u32 eax, ebx, ecx, edx;
+ char hyp_signature[13];
+
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+ if (!(ecx & HYPERV_HYPERVISOR_PRESENT_BIT))
+ return 0;
+
+ cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, &eax, &ebx, &ecx, &edx);
+ *(u32 *)(hyp_signature + 0) = ebx;
+ *(u32 *)(hyp_signature + 4) = ecx;
+ *(u32 *)(hyp_signature + 8) = edx;
+
+ if ((eax < HYPERV_CPUID_MIN) || (memcmp("Microsoft Hv", hyp_signature, 12)))
+ return 0;
+ return 1;
+}
+
+void __cpuinit hyperv_set_feature_bits(struct cpuinfo_x86 *c)
+{
+ u32 eax, ebx, ecx, edx;
+
+ c->x86_hyper_features = 0;
+ /*
+ * Extract the features, recommendations etc.
+ * The first 9 bits will be used to track hypervisor features.
+ * The next 6 bits will be used to track the hypervisor
+ * recommendations.
+ */
+ cpuid(HYPERV_CPUID_FEATURES, &eax, &ebx, &ecx, &edx);
+ c->x86_hyper_features |= (eax & 0x1ff);
+
+ cpuid(HYPERV_CPUID_ENLIGHTMENT_INFO, &eax, &ebx, &ecx, &edx);
+ c->x86_hyper_features |= ((eax & 0x3f) << 9);
+ printk(KERN_INFO "Detected HyperV with features: %x\n",
+ c->x86_hyper_features);
+}
Index: linux-2.6.34-rc4/arch/x86/kernel/cpu/hypervisor.c
===================================================================
--- linux-2.6.34-rc4.orig/arch/x86/kernel/cpu/hypervisor.c 2010-04-12 19:41:35.000000000 -0600
+++ linux-2.6.34-rc4/arch/x86/kernel/cpu/hypervisor.c 2010-04-15 10:00:18.000000000 -0600
@@ -23,6 +23,7 @@
#include <asm/processor.h>
#include <asm/vmware.h>
+#include <asm/hyperv.h>
#include <asm/hypervisor.h>
static inline void __cpuinit
@@ -30,6 +31,8 @@ detect_hypervisor_vendor(struct cpuinfo_
{
if (vmware_platform())
c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE;
+ else if (hyperv_platform())
+ c->x86_hyper_vendor = X86_HYPER_VENDOR_MSFT;
else
c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE;
}
@@ -37,10 +40,11 @@ detect_hypervisor_vendor(struct cpuinfo_
static inline void __cpuinit
hypervisor_set_feature_bits(struct cpuinfo_x86 *c)
{
- if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) {
+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE)
vmware_set_feature_bits(c);
- return;
- }
+ else if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_MSFT)
+ hyperv_set_feature_bits(c);
+ return;
}
void __cpuinit init_hypervisor(struct cpuinfo_x86 *c)
Index: linux-2.6.34-rc4/arch/x86/include/asm/hyperv.h
===================================================================
--- linux-2.6.34-rc4.orig/arch/x86/include/asm/hyperv.h 2010-04-12 19:41:35.000000000 -0600
+++ linux-2.6.34-rc4/arch/x86/include/asm/hyperv.h 2010-04-15 13:06:58.000000000 -0600
@@ -2,6 +2,8 @@
#define _ASM_X86_KVM_HYPERV_H
#include <linux/types.h>
+#include <linux/init.h>
+#include <asm/processor.h>
/*
* The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
@@ -14,6 +16,9 @@
#define HYPERV_CPUID_ENLIGHTMENT_INFO 0x40000004
#define HYPERV_CPUID_IMPLEMENT_LIMITS 0x40000005
+#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000
+#define HYPERV_CPUID_MIN 0x40000005
+
/*
* Feature identification. EAX indicates which features are available
* to the partition based upon the current partition privileges.
@@ -129,6 +134,9 @@
/* MSR used to provide vcpu index */
#define HV_X64_MSR_VP_INDEX 0x40000002
+/* MSR used to read the per-partition time reference counter */
+#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
+
/* Define the virtual APIC registers */
#define HV_X64_MSR_EOI 0x40000070
#define HV_X64_MSR_ICR 0x40000071
@@ -183,4 +191,6 @@
#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
#define HV_STATUS_INVALID_ALIGNMENT 4
+int hyperv_platform(void);
+void __cpuinit hyperv_set_feature_bits(struct cpuinfo_x86 *c);
#endif
[-- Attachment #3: hyperv_clocksource.patch --]
[-- Type: text/plain, Size: 4366 bytes --]
From: K. Y. Srinivasan <ksrinivasan@novell.com>
Subject: A clocksource for Linux guests hosted on HyperV.
References: None
Patch-mainline:
This patch is a clocksource implementation suitable for guests hosted on HyperV.
Time keeping in Linux guests hosted on HyperV is unstable. This clocksource
driver fixes the problem.
Signed-off-by: K. Y. Srinivasan <ksrinivasan@novell.com>
Index: linux-2.6.34-rc4/drivers/staging/hv/hv_timesource.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.34-rc4/drivers/staging/hv/hv_timesource.c 2010-04-15 13:45:46.000000000 -0600
@@ -0,0 +1,97 @@
+/*
+ * A clocksource for Linux running on HyperV.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <asm/hyperv.h>
+
+#define HV_CLOCK_SHIFT 22
+
+static cycle_t read_hv_clock(struct clocksource *arg)
+{
+ cycle_t current_tick;
+ /*
+ * Read the partition counter to get the current tick count. This count
+ * is set to 0 when the partition is created and is incremented in
+ * 100 nanosecond units.
+ */
+ rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+ return current_tick;
+}
+
+static struct clocksource hyperv_cs = {
+ .name = "hyperv_clocksource",
+ .rating = 400, /* use this when running on Hyperv*/
+ .read = read_hv_clock,
+ .mask = CLOCKSOURCE_MASK(64),
+ /*
+ * The time ref counter in HyperV is in 100ns units.
+ * The definition of mult is:
+ * mult/2^shift = ns/cyc = 100
+ * mult = (100 << shift)
+ */
+ .mult = (100 << HV_CLOCK_SHIFT),
+ .shift = HV_CLOCK_SHIFT,
+};
+
+static const struct dmi_system_id __initconst
+hv_timesource_dmi_table[] __maybe_unused = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table);
+
+static const struct pci_device_id __initconst
+hv_timesource_pci_table[] __maybe_unused = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table);
+
+
+static int __init init_hv_clocksource(void)
+{
+ if ((boot_cpu_data.x86_hyper_vendor != X86_HYPER_VENDOR_MSFT) ||
+ !(boot_cpu_data.x86_hyper_features &
+ HV_X64_MSR_TIME_REF_COUNT_AVAILABLE))
+ return -ENODEV;
+ printk(KERN_INFO "Registering HyperV clock source\n");
+ return clocksource_register(&hyperv_cs);
+}
+
+module_init(init_hv_clocksource);
+MODULE_DESCRIPTION("HyperV based clocksource");
+MODULE_AUTHOR("K. Y. Srinivasan <ksrinivasan@novell.com>");
+MODULE_LICENSE("GPL");
Index: linux-2.6.34-rc4/drivers/staging/hv/Makefile
===================================================================
--- linux-2.6.34-rc4.orig/drivers/staging/hv/Makefile 2010-04-12 19:41:35.000000000 -0600
+++ linux-2.6.34-rc4/drivers/staging/hv/Makefile 2010-04-15 13:09:07.000000000 -0600
@@ -1,4 +1,4 @@
-obj-$(CONFIG_HYPERV) += hv_vmbus.o
+obj-$(CONFIG_HYPERV) += hv_vmbus.o hv_timesource.o
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
[-- Attachment #4: Type: text/plain, Size: 184 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* [PULL] lguest fixes: for lguest-under-kvm and older CPU configs
From: Rusty Russell @ 2010-04-14 12:17 UTC (permalink / raw)
To: Linus Torvalds; +Cc: lguest, Matias Zabaljauregui, virtualization
The following changes since commit 2ba3abd8186f24c7fb418927025b4e2120e3a362:
Linus Torvalds (1):
Merge branch 'pm-fixes' of git://git.kernel.org/.../rafael/suspend-2.6
are available in the git repository at:
ssh://master.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus.git master
Rusty Russell (2):
lguest: workaround cmpxchg8b_emu by ignoring cli in the guest.
lguest: stop using KVM hypercall mechanism
arch/x86/include/asm/lguest_hcall.h | 29 +++++++++++++---
arch/x86/lguest/boot.c | 61 +++++++++++++++++------------------
arch/x86/lguest/i386_head.S | 2 +-
drivers/lguest/lguest_device.c | 4 +-
drivers/lguest/x86/core.c | 12 +++++++
5 files changed, 68 insertions(+), 40 deletions(-)
commit 5094aeafbbd500509f648e3cd102b053bc7926b3
Author: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed Apr 14 21:43:53 2010 -0600
lguest: workaround cmpxchg8b_emu by ignoring cli in the guest.
It's only used by cmpxchg8b_emu (see db677ffa5f5a for the gory
details), and fixing that to be paravirt aware would be more work than
simply ignoring it (and AFAICT only help lguest). This makes lguest
work on machines which have cmpxchg8b, for kernels compiled for older
processors.
(We can't emulate it properly: the popf which expects to restore interrupts
does not trap).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: virtualization@lists.osdl.org
drivers/lguest/x86/core.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
commit 091ebf07a2408f9a56634caa0f86d9360e9af23b
Author: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed Apr 14 21:43:54 2010 -0600
lguest: stop using KVM hypercall mechanism
This is a partial revert of 4cd8b5e2a159 "lguest: use KVM hypercalls";
we revert to using (just as questionable but more reliable) int $15 for
hypercalls. I didn't revert the register mapping, so we still use the
same calling convention as kvm.
KVM in more recent incarnations stopped injecting a fault when a guest
tried to use the VMCALL instruction from ring 1, so lguest under kvm
fails to make hypercalls. It was nice to share code with our KVM
cousins, but this was overreach.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Matias Zabaljauregui <zabaljauregui@gmail.com>
Cc: Avi Kivity <avi@redhat.com>
arch/x86/include/asm/lguest_hcall.h | 29 +++++++++++++---
arch/x86/lguest/boot.c | 61 +++++++++++++++++------------------
arch/x86/lguest/i386_head.S | 2 +-
drivers/lguest/lguest_device.c | 4 +-
4 files changed, 56 insertions(+), 40 deletions(-)
^ permalink raw reply
* Re: [PULL] virtio console fixes, abi change
From: Juan Quintela @ 2010-04-14 7:25 UTC (permalink / raw)
To: Amit Shah; +Cc: Virtualization List
In-Reply-To: <20100414053557.GA4442@amit-x200.redhat.com>
Amit Shah <amit.shah@redhat.com> wrote:
> Hello Rusty,
>
> To avoid sending the same patches again, this time I'm trying a git pull
> request.
>
> Please pull from
>
> git://git.kernel.org/pub/scm/linux/kernel/git/amit/vs-kernel.git for-rusty
>
> to get the patches that I've sent to the list previously, with a couple
> of fixes:
>
> - Create a console port when not using multiport (fix was sent as a
> reply to prev. series)
>
> - Add hunk that got inadvertently reverted during git rebase operations
> (thanks Juan).
>
> The diff to the v6 version is attached below:
Acked-by: Juan Quintela <quintela@redhat.com>
^ permalink raw reply
* [PULL] virtio console fixes, abi change
From: Amit Shah @ 2010-04-14 5:35 UTC (permalink / raw)
To: Rusty Russell; +Cc: Juan Quintela, Virtualization List
Hello Rusty,
To avoid sending the same patches again, this time I'm trying a git pull
request.
Please pull from
git://git.kernel.org/pub/scm/linux/kernel/git/amit/vs-kernel.git for-rusty
to get the patches that I've sent to the list previously, with a couple
of fixes:
- Create a console port when not using multiport (fix was sent as a
reply to prev. series)
- Add hunk that got inadvertently reverted during git rebase operations
(thanks Juan).
The diff to the v6 version is attached below:
diff --git a/drivers/char/virtio_console.c
b/drivers/char/virtio_console.c
index b06a0e5..a64558f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1083,6 +1083,8 @@ free_cdev:
free_port:
kfree(port);
fail:
+ /* The host might want to notify management sw about port add
failure */
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 0);
return err;
}
@@ -1407,17 +1513,14 @@ static int __devinit virtcons_probe(struct
virtio_device *vdev)
err = -ENOMEM;
goto free_vqs;
}
+ } else {
+ /*
+ * For backward compatibility: Create a console port
+ * if we're running on older host.
+ */
+ add_port(portdev, 0);
}
Thanks,
Amit
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox