From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-09-28 09:24:35
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
We could get rid of an extra s/g for big packets too,
but since in practice everyone enables mergeable buffers,
I don't see much of a point.
Rusty, if you decide to pick this up I'll send a
(rather trivial) spec patch shortly afterwards, but holidays
are beginning here. Considering how simple
the guest patch is, I hope it can make it in 3.7?
Also note that patch 1 and 2 are IMO a good
idea without patch 3. If you decide to defer patch 3
pls consider 1/2 separately.
Before:
[root@virtlab203 qemu]# ssh robin ./netperf/bin/netperf -t TCP_RR -H
11.0.0.4
TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
11.0.0.4 (11.0.0.4) port 0 AF_INET : demo
Local /Remote
Socket Size Request Resp. Elapsed Trans.
Send Recv Size Size Time Rate
bytes Bytes bytes bytes secs. per sec
16384 87380 1 1 10.00 2992.88
16384 87380
After:
[root@virtlab203 qemu]# ssh robin ./netperf/bin/netperf -t TCP_RR -H
11.0.0.4
TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
11.0.0.4 (11.0.0.4) port 0 AF_INET : demo
Local /Remote
Socket Size Request Resp. Elapsed Trans.
Send Recv Size Size Time Rate
bytes Bytes bytes bytes secs. per sec
16384 87380 1 1 10.00 3195.57
16384 87380
Michael S. Tsirkin (3):
virtio: add API to query ring capacity
virtio-net: correct capacity math on ring full
virtio-net: put virtio net header inline with data
drivers/net/virtio_net.c | 57 +++++++++++++++++++++++++++++++-------------
drivers/virtio/virtio_ring.c | 19 +++++++++++++++
include/linux/virtio.h | 2 ++
include/linux/virtio_net.h | 5 +++-
4 files changed, 66 insertions(+), 17 deletions(-)
--
MST
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-09-28 09:24:41
It's sometimes necessary to query ring capacity after dequeueing a
buffer. Add an API for this.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
drivers/virtio/virtio_ring.c | 19 +++++++++++++++++++
include/linux/virtio.h | 2 ++
2 files changed, 21 insertions(+)
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-09-28 09:24:44
Capacity math on ring full is wrong: we are
looking at num_sg but that might be optimistic
because of indirect buffer use.
The implementation also penalizes fast path
with extra memory accesses for the benefit of
ring full condition handling which is slow path.
It's easy to query ring capacity so let's do just that.
This change also makes it easier to move vnet header
for tx around as follow-up patch does.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
drivers/net/virtio_net.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-09-28 09:25:13
For small packets we can simplify xmit processing
by linearizing buffers with the header:
most packets seem to have enough head room
we can use for this purpose.
Since existing hypervisors require that header
is the first s/g element, we need a feature bit
for this.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
drivers/net/virtio_net.c | 44 +++++++++++++++++++++++++++++++++++---------
include/linux/virtio_net.h | 5 ++++-
2 files changed, 39 insertions(+), 10 deletions(-)
@@ -67,6 +67,9 @@ struct virtnet_info {/* Host will merge rx buffers for big packets (shake it! shake it!) */boolmergeable_rx_bufs;+/* Host can handle any s/g split between our header and packet data */+boolany_header_sg;+/* enable config space updates */boolconfig_enable;
@@ -576,11 +579,28 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)staticintxmit_skb(structvirtnet_info*vi,structsk_buff*skb){-structskb_vnet_hdr*hdr=skb_vnet_hdr(skb);+structskb_vnet_hdr*hdr;constunsignedchar*dest=((structethhdr*)skb->data)->h_dest;unsignednum_sg;+unsignedhdr_len;+boolcan_push;+pr_debug("%s: xmit %p %pM\n",vi->dev->name,skb,dest);+if(vi->mergeable_rx_bufs)+hdr_len=sizeofhdr->mhdr;+else+hdr_len=sizeofhdr->hdr;++can_push=vi->any_header_sg&&+!((unsignedlong)skb->data&(__alignof__(*hdr)-1))&&+!skb_header_cloned(skb)&&skb_headroom(skb)>=hdr_len;+/* Even if we can, don't push here yet as this would skew+*csum_startoffsetbelow.*/+if(can_push)+hdr=(structskb_vnet_hdr*)(skb->data-hdr_len);+else+hdr=skb_vnet_hdr(skb);if(skb->ip_summed==CHECKSUM_PARTIAL){hdr->hdr.flags=VIRTIO_NET_HDR_F_NEEDS_CSUM;
@@ -609,15 +629,18 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)hdr->hdr.gso_size=hdr->hdr.hdr_len=0;}-hdr->mhdr.num_buffers=0;--/* Encode metadata header at front. */if(vi->mergeable_rx_bufs)-sg_set_buf(vi->tx_sg,&hdr->mhdr,sizeofhdr->mhdr);-else-sg_set_buf(vi->tx_sg,&hdr->hdr,sizeofhdr->hdr);+hdr->mhdr.num_buffers=0;-num_sg=skb_to_sgvec(skb,vi->tx_sg+1,0,skb->len)+1;+if(can_push){+__skb_push(skb,hdr_len);+num_sg=skb_to_sgvec(skb,vi->tx_sg,0,skb->len);+/* Pull header back to avoid skew in tx bytes calculations. */+__skb_pull(skb,hdr_len);+}else{+sg_set_buf(vi->tx_sg,hdr,hdr_len);+num_sg=skb_to_sgvec(skb,vi->tx_sg+1,0,skb->len)+1;+}returnvirtqueue_add_buf(vi->svq,vi->tx_sg,num_sg,0,skb,GFP_ATOMIC);}
@@ -1128,6 +1151,9 @@ static int virtnet_probe(struct virtio_device *vdev)if(virtio_has_feature(vdev,VIRTIO_NET_F_MRG_RXBUF))vi->mergeable_rx_bufs=true;+if(virtio_has_feature(vdev,VIRTIO_NET_F_ANY_HEADER_SG))+vi->any_header_sg=true;+err=init_vqs(vi);if(err)gotofree_stats;
@@ -1286,7 +1312,7 @@ static unsigned int features[] = {VIRTIO_NET_F_GUEST_ECN,VIRTIO_NET_F_GUEST_UFO,VIRTIO_NET_F_MRG_RXBUF,VIRTIO_NET_F_STATUS,VIRTIO_NET_F_CTRL_VQ,VIRTIO_NET_F_CTRL_RX,VIRTIO_NET_F_CTRL_VLAN,-VIRTIO_NET_F_GUEST_ANNOUNCE,+VIRTIO_NET_F_GUEST_ANNOUNCE,VIRTIO_NET_F_ANY_HEADER_SG};staticstructvirtio_drivervirtio_net_driver={
@@ -51,6 +51,7 @@#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce device on the*network*/+#define VIRTIO_NET_F_ANY_HEADER_SG 22 /* Host can handle any header s/g */#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
@@ -62,7 +63,9 @@ struct virtio_net_config {__u16status;}__attribute__((packed));-/* This is the first element of the scatter-gather list. If you don't+/* This header comes first in the scatter-gather list.+*IfVIRTIO_NET_F_ANY_HEADER_SGisnotnegotiated,itmust+*bethefirstelementofthescatter-gatherlist.Ifyoudon't*specifyGSOorCSUMfeatures,youcansimplyignoretheheader.*/structvirtio_net_hdr{#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
From: Rusty Russell <hidden> Date: 2012-10-03 07:02:46
"Michael S. Tsirkin" [off-list ref] writes:
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
So my plan was to tie this assumption to the new PCI layout. And have a
stress-testing patch like the one below in the kernel (see my virtio-wip
branch for stuff like this). Turn it on at boot with
"virtio_ring.torture" on the kernel commandline.
BTW, I've fixed lguest, but my kvm here (Ubuntu precise, kvm-qemu 1.0)
is too old. Building the latest git now...
Cheers,
Rusty.
Subject: virtio: CONFIG_VIRTIO_DEVICE_TORTURE
Virtio devices are not supposed to depend on the framing of the scatter-gather
lists, but various implementations did. Safeguard this in future by adding
an option to deliberately create perverse descriptors.
Signed-off-by: Rusty Russell <redacted>
@@ -124,6 +124,149 @@ struct vring_virtqueue#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)+#ifdef CONFIG_VIRTIO_DEVICE_TORTURE+staticbooltorture;+module_param(torture,bool,0644);++structtorture{+unsignedintorig_out,orig_in;+void*orig_data;+structscatterlistsg[4];+structscatterlistorig_sg[];+};++staticsize_ttot_len(structscatterlistsg[],unsignednum)+{+size_tlen,i;++for(len=0,i=0;i<num;i++)+len+=sg[i].length;++returnlen;+}++staticvoidcopy_sg_data(conststructscatterlist*dst,unsigneddnum,+conststructscatterlist*src,unsignedsnum)+{+unsignedlen;+structscatterlists,d;++s=*src;+d=*dst;++while(snum&&dnum){+len=min(s.length,d.length);+memcpy(sg_virt(&d),sg_virt(&s),len);+d.offset+=len;+d.length-=len;+s.offset+=len;+s.length-=len;+if(!s.length){+BUG_ON(snum==0);+src++;+snum--;+s=*src;+}+if(!d.length){+BUG_ON(dnum==0);+dst++;+dnum--;+d=*dst;+}+}+}++staticbooltorture_replace(structscatterlist**sg,+unsignedint*out,+unsignedint*in,+void**data,+gfp_tgfp)+{+staticsize_tseed;+structtorture*t;+size_toutlen,inlen,ourseed,len1;+void*buf;++if(!torture)+returntrue;++outlen=tot_len(*sg,*out);+inlen=tot_len(*sg+*out,*in);++/* This will break horribly on large block requests. */+t=kmalloc(sizeof(*t)+(*out+*in)*sizeof(t->orig_sg[1])++outlen+1+inlen+1,gfp);+if(!t)+returnfalse;++sg_init_table(t->sg,4);+buf=&t->orig_sg[*out+*in];++memcpy(t->orig_sg,*sg,sizeof(**sg)*(*out+*in));+t->orig_out=*out;+t->orig_in=*in;+t->orig_data=*data;+*data=t;++ourseed=ACCESS_ONCE(seed);+seed++;++*sg=t->sg;+if(outlen){+/* Split outbuf into two parts, one byte apart. */+*out=2;+len1=ourseed%(outlen+1);+sg_set_buf(&t->sg[0],buf,len1);+buf+=len1+1;+sg_set_buf(&t->sg[1],buf,outlen-len1);+buf+=outlen-len1;+copy_sg_data(t->sg,*out,t->orig_sg,t->orig_out);+}++if(inlen){+/* Split inbuf into two parts, one byte apart. */+*in=2;+len1=ourseed%(inlen+1);+sg_set_buf(&t->sg[*out],buf,len1);+buf+=len1+1;+sg_set_buf(&t->sg[*out+1],buf,inlen-len1);+buf+=inlen-len1;+}+returntrue;+}++staticvoid*torture_done(structtorture*t)+{+void*data;++if(!torture)+returnt;++if(t->orig_in)+copy_sg_data(t->orig_sg+t->orig_out,t->orig_in,+t->sg+(t->orig_out?2:0),2);++data=t->orig_data;+kfree(t);+returndata;+}++#else+staticbooltorture_replace(structscatterlist**sg,+unsignedint*out,+unsignedint*in,+void**data,+gfp_tgfp)+{+returntrue;+}++staticvoid*torture_done(void*data)+{+returndata;+}+#endif /* CONFIG_VIRTIO_DEVICE_TORTURE */+/* Set up an indirect table of descriptors and add it to the queue. */staticintvring_add_indirect(structvring_virtqueue*vq,structscatterlistsg[],
@@ -213,6 +356,9 @@ int virtqueue_add_buf(struct virtqueue *_vq,BUG_ON(data==NULL);+if(!torture_replace(&sg,&out,&in,&data,gfp))+return-ENOMEM;+#ifdef DEBUG{ktime_tnow=ktime_get();
@@ -246,6 +392,7 @@ int virtqueue_add_buf(struct virtqueue *_vq,if(out)vq->notify(&vq->vq);END_USE(vq);+torture_done(data);return-ENOSPC;}
From: Rusty Russell <hidden> Date: 2012-10-03 22:27:47
Rusty Russell [off-list ref] writes:
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
Breaks for me; see why I hate bug features? Now we'd need another
one...
qemu-system-i386: virtio: trying to map MMIO memory
Please try my patch.
Cheers,
Rusty.
From: Rusty Russell <hidden> Date: 2012-10-04 01:24:19
"Michael S. Tsirkin" [off-list ref] writes:
Capacity math on ring full is wrong: we are
looking at num_sg but that might be optimistic
because of indirect buffer use.
The implementation also penalizes fast path
with extra memory accesses for the benefit of
ring full condition handling which is slow path.
It's easy to query ring capacity so let's do just that.
This path will reduce the actual queue use to worst-case assumptions.
With bufferbloat maybe that's a good thing, but it's true.
If we do this, the code is now wrong:
/* This can happen with OOM and indirect buffers. */
if (unlikely(capacity < 0)) {
Because this should now *never* happen.
But I do like the cleanup; returning capacity from add_buf() was always
hacky. I've got an idea, we'll see what it looks like...
Cheers,
Rusty.
From: Anthony Liguori <hidden> Date: 2012-10-04 01:24:54
Rusty Russell [off-list ref] writes:
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
This is a bug in the specification.
The QEMU implementation pre-dates the specification. All of the actual
implementations of virtio relied on the semantics of s/g elements and
still do.
What's in the specification really doesn't matter when it doesn't agree
with all of the existing implementations.
Users use implementations, not specifications. The specification really
ought to be changed here.
Regards,
Anthony Liguori
From: Anthony Liguori <hidden> Date: 2012-10-04 01:35:08
Rusty Russell [off-list ref] writes:
"Michael S. Tsirkin" [off-list ref] writes:
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
So my plan was to tie this assumption to the new PCI layout. And have a
stress-testing patch like the one below in the kernel (see my virtio-wip
branch for stuff like this). Turn it on at boot with
"virtio_ring.torture" on the kernel commandline.
BTW, I've fixed lguest, but my kvm here (Ubuntu precise, kvm-qemu 1.0)
is too old. Building the latest git now...
Cheers,
Rusty.
Subject: virtio: CONFIG_VIRTIO_DEVICE_TORTURE
Virtio devices are not supposed to depend on the framing of the scatter-gather
lists, but various implementations did. Safeguard this in future by adding
an option to deliberately create perverse descriptors.
Signed-off-by: Rusty Russell <redacted>
Ignore framing is really a bad idea. You want backends to enforce
reasonable framing because guest's shouldn't do silly things with framing.
For instance, with virtio-blk, if you want decent performance, you
absolutely want to avoid bouncing the data. If you're using O_DIRECT in
the host to submit I/O requests, then it's critical that all of the s/g
elements are aligned to a sector boundary and sized to a sector
boundary.
Yes, QEMU can handle if that's not the case, but it would be insanely
stupid for a guest not to do this. This is the sort of thing that ought
to be enforced in the specification because a guest cannot perform well
if it doesn't follow these rules.
A spec isn't terribly useful if the result is guest drivers that are
slow. There's very little to gain by not enforcing rules around framing
and there's a lot to lose if a guest frames incorrectly.
In the rare case where we want to make a framing change, we should use
feature bits like Michael is proposing.
In this case, we should simply say that with the feature bit, the vnet
header can be in the same element as the data but not allow the header
to be spread across multiple elements.
Regards,
Anthony Liguori
@@ -124,6 +124,149 @@ struct vring_virtqueue#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)+#ifdef CONFIG_VIRTIO_DEVICE_TORTURE+staticbooltorture;+module_param(torture,bool,0644);++structtorture{+unsignedintorig_out,orig_in;+void*orig_data;+structscatterlistsg[4];+structscatterlistorig_sg[];+};++staticsize_ttot_len(structscatterlistsg[],unsignednum)+{+size_tlen,i;++for(len=0,i=0;i<num;i++)+len+=sg[i].length;++returnlen;+}++staticvoidcopy_sg_data(conststructscatterlist*dst,unsigneddnum,+conststructscatterlist*src,unsignedsnum)+{+unsignedlen;+structscatterlists,d;++s=*src;+d=*dst;++while(snum&&dnum){+len=min(s.length,d.length);+memcpy(sg_virt(&d),sg_virt(&s),len);+d.offset+=len;+d.length-=len;+s.offset+=len;+s.length-=len;+if(!s.length){+BUG_ON(snum==0);+src++;+snum--;+s=*src;+}+if(!d.length){+BUG_ON(dnum==0);+dst++;+dnum--;+d=*dst;+}+}+}++staticbooltorture_replace(structscatterlist**sg,+unsignedint*out,+unsignedint*in,+void**data,+gfp_tgfp)+{+staticsize_tseed;+structtorture*t;+size_toutlen,inlen,ourseed,len1;+void*buf;++if(!torture)+returntrue;++outlen=tot_len(*sg,*out);+inlen=tot_len(*sg+*out,*in);++/* This will break horribly on large block requests. */+t=kmalloc(sizeof(*t)+(*out+*in)*sizeof(t->orig_sg[1])++outlen+1+inlen+1,gfp);+if(!t)+returnfalse;++sg_init_table(t->sg,4);+buf=&t->orig_sg[*out+*in];++memcpy(t->orig_sg,*sg,sizeof(**sg)*(*out+*in));+t->orig_out=*out;+t->orig_in=*in;+t->orig_data=*data;+*data=t;++ourseed=ACCESS_ONCE(seed);+seed++;++*sg=t->sg;+if(outlen){+/* Split outbuf into two parts, one byte apart. */+*out=2;+len1=ourseed%(outlen+1);+sg_set_buf(&t->sg[0],buf,len1);+buf+=len1+1;+sg_set_buf(&t->sg[1],buf,outlen-len1);+buf+=outlen-len1;+copy_sg_data(t->sg,*out,t->orig_sg,t->orig_out);+}++if(inlen){+/* Split inbuf into two parts, one byte apart. */+*in=2;+len1=ourseed%(inlen+1);+sg_set_buf(&t->sg[*out],buf,len1);+buf+=len1+1;+sg_set_buf(&t->sg[*out+1],buf,inlen-len1);+buf+=inlen-len1;+}+returntrue;+}++staticvoid*torture_done(structtorture*t)+{+void*data;++if(!torture)+returnt;++if(t->orig_in)+copy_sg_data(t->orig_sg+t->orig_out,t->orig_in,+t->sg+(t->orig_out?2:0),2);++data=t->orig_data;+kfree(t);+returndata;+}++#else+staticbooltorture_replace(structscatterlist**sg,+unsignedint*out,+unsignedint*in,+void**data,+gfp_tgfp)+{+returntrue;+}++staticvoid*torture_done(void*data)+{+returndata;+}+#endif /* CONFIG_VIRTIO_DEVICE_TORTURE */+/* Set up an indirect table of descriptors and add it to the queue. */staticintvring_add_indirect(structvring_virtqueue*vq,structscatterlistsg[],
@@ -213,6 +356,9 @@ int virtqueue_add_buf(struct virtqueue *_vq,BUG_ON(data==NULL);+if(!torture_replace(&sg,&out,&in,&data,gfp))+return-ENOMEM;+#ifdef DEBUG{ktime_tnow=ktime_get();
@@ -246,6 +392,7 @@ int virtqueue_add_buf(struct virtqueue *_vq,if(out)vq->notify(&vq->vq);END_USE(vq);+torture_done(data);return-ENOSPC;}
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Rusty Russell <hidden> Date: 2012-10-04 03:52:51
Anthony Liguori [off-list ref] writes:
Rusty Russell [off-list ref] writes:
quoted
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
This is a bug in the specification.
The QEMU implementation pre-dates the specification. All of the actual
implementations of virtio relied on the semantics of s/g elements and
still do.
lguest fix is pending in my queue. lkvm and qemu are broken; lkvm isn't
ever going to be merged, so I'm not sure what its status is? But I'm
determined to fix qemu, and hence my torture patch to make sure this
doesn't creep in again.
What's in the specification really doesn't matter when it doesn't agree
with all of the existing implementations.
Users use implementations, not specifications. The specification really
ought to be changed here.
I'm sorely tempted, except that we're losing a real optimization because
of this :(
The specification has long contained the footnote:
The current qemu device implementations mistakenly insist that
the first descriptor cover the header in these cases exactly, so
a cautious driver should arrange it so.
I'd like to tie this caveat to the PCI capability change, so this note
will move to the appendix with the old PCI layout.
Cheers,
Rusty.
From: Anthony Liguori <hidden> Date: 2012-10-04 04:29:54
Rusty Russell [off-list ref] writes:
Anthony Liguori [off-list ref] writes:
quoted
Rusty Russell [off-list ref] writes:
quoted
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
This is a bug in the specification.
The QEMU implementation pre-dates the specification. All of the actual
implementations of virtio relied on the semantics of s/g elements and
still do.
lguest fix is pending in my queue. lkvm and qemu are broken; lkvm isn't
ever going to be merged, so I'm not sure what its status is? But I'm
determined to fix qemu, and hence my torture patch to make sure this
doesn't creep in again.
There are even more implementations out there and I'd wager they all
rely on framing.
quoted
What's in the specification really doesn't matter when it doesn't agree
with all of the existing implementations.
Users use implementations, not specifications. The specification really
ought to be changed here.
I'm sorely tempted, except that we're losing a real optimization because
of this :(
What optimizations? What Michael is proposing is still achievable with
a device feature. Are there other optimizations that can be achieved by
changing framing that we can't achieve with feature bits?
As I mentioned in another note, bad framing decisions can cause
performance issues too...
The specification has long contained the footnote:
The current qemu device implementations mistakenly insist that
the first descriptor cover the header in these cases exactly, so
a cautious driver should arrange it so.
I seem to recall this being a compromise between you and I.. I think
I objected strongly to this back when you first wrote the spec and you
added this to appease me ;-)
Regards,
Anthony Liguori
I'd like to tie this caveat to the PCI capability change, so this note
will move to the appendix with the old PCI layout.
Cheers,
Rusty.
From: Rusty Russell <hidden> Date: 2012-10-04 05:44:15
Anthony Liguori [off-list ref] writes:
Rusty Russell [off-list ref] writes:
quoted
"Michael S. Tsirkin" [off-list ref] writes:
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
So my plan was to tie this assumption to the new PCI layout. And have a
stress-testing patch like the one below in the kernel (see my virtio-wip
branch for stuff like this). Turn it on at boot with
"virtio_ring.torture" on the kernel commandline.
BTW, I've fixed lguest, but my kvm here (Ubuntu precise, kvm-qemu 1.0)
is too old. Building the latest git now...
Cheers,
Rusty.
Subject: virtio: CONFIG_VIRTIO_DEVICE_TORTURE
Virtio devices are not supposed to depend on the framing of the scatter-gather
lists, but various implementations did. Safeguard this in future by adding
an option to deliberately create perverse descriptors.
Signed-off-by: Rusty Russell <redacted>
Ignore framing is really a bad idea. You want backends to enforce
reasonable framing because guest's shouldn't do silly things with framing.
For instance, with virtio-blk, if you want decent performance, you
absolutely want to avoid bouncing the data. If you're using O_DIRECT in
the host to submit I/O requests, then it's critical that all of the s/g
elements are aligned to a sector boundary and sized to a sector
boundary.
Yes, QEMU can handle if that's not the case, but it would be insanely
stupid for a guest not to do this. This is the sort of thing that ought
to be enforced in the specification because a guest cannot perform well
if it doesn't follow these rules.
Lack of imagination is what got us into trouble in the first place; when
presented with one counter-example, it's useful to look for others.
That's our job, not to dismiss them a "insanely stupid".
For example:
1) Perhaps the guest isn't trying to perform well, it's trying to be a
tiny bootloader?
2) Perhaps the guest is the direct consumer, and aligning buffers is
redundant.
A spec isn't terribly useful if the result is guest drivers that are
slow. There's very little to gain by not enforcing rules around framing
and there's a lot to lose if a guest frames incorrectly.
The guest has the flexibility, and gets to decide. The spec is not
forcing them to perform badly.
In the rare case where we want to make a framing change, we should use
feature bits like Michael is proposing.
In this case, we should simply say that with the feature bit, the vnet
header can be in the same element as the data but not allow the header
to be spread across multiple elements.
I'd love to split struct virtio_net_hdr_mrg_rxbuf, so the num_buffers
ends up somewhere else.
The simplest rules are "never" or "always".
Cheers,
Rusty.
PS. Inserting zero-length buffers is something I'd be prepared to rule
out, my current patch does it just for yuks...
From: Rusty Russell <hidden> Date: 2012-10-04 08:02:21
Anthony Liguori [off-list ref] writes:
quoted
lguest fix is pending in my queue. lkvm and qemu are broken; lkvm isn't
ever going to be merged, so I'm not sure what its status is? But I'm
determined to fix qemu, and hence my torture patch to make sure this
doesn't creep in again.
There are even more implementations out there and I'd wager they all
rely on framing.
Worse, both virtio_blk (for scsi commands) and virtio_scsi explicitly
and inescapably rely on framing. The spec conflicts clearly with
itself.
Such layering violations are always a mistake, but I can't blame anyone
else for my lack of attention :(
Here's the spec change:
commit 7e74459bb966ccbaad9e4bf361d1178b7f400b79
Author: Rusty Russell [off-list ref]
Date: Thu Oct 4 17:11:27 2012 +0930
No longer assume framing is independent of messages. *sniff*
Signed-off-by: Rusty Russell <redacted>
@@ -880,19 +880,19 @@ Message Framing-The descriptors used for a buffer should not effect the semantics-of the message, except for the total length of the buffer. For-example, a network buffer consists of a 10 byte header followed-by the network packet. Whether this is presented in the ring-descriptor chain as (say) a 10 byte buffer and a 1514 byte-buffer, or a single 1524 byte buffer, or even three buffers,-should have no effect.+Unless stated otherwise, it is expected that headers within a+message are contained within their own descriptors. For example,+a network buffer consists of a 10 or 12 byte header followed by+the network packet. An implementation should expect that this+header will be within the first descriptor, and that the+remainder of the data will begin on the second descriptor.-In particular, no implementation should use the descriptor-boundaries to determine the size of any header in a request.[footnote:-The current qemu device implementations mistakenly insist that-the first descriptor cover the header in these cases exactly, so-a cautious driver should arrange it so.+[footnote:+It was previously asserted that framing should be independent of+message contents, yet invariably drivers layed out messages in+reliable ways and devices assumed it. In addition, the+specifications for virtio_blk and virtio_scsi require intuiting+field lengths from frame boundaries. ] Device Improvements
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2012-10-05 07:47:25
Il 04/10/2012 09:44, Rusty Russell ha scritto:
-In particular, no implementation should use the descriptor
-boundaries to determine the size of any header in a request.[footnote:
-The current qemu device implementations mistakenly insist that
-the first descriptor cover the header in these cases exactly, so
-a cautious driver should arrange it so.
+[footnote:
+It was previously asserted that framing should be independent of
+message contents, yet invariably drivers layed out messages in
+reliable ways and devices assumed it. In addition, the
+specifications for virtio_blk and virtio_scsi require intuiting
+field lengths from frame boundaries.
]
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-10-08 19:40:05
On Wed, Oct 03, 2012 at 04:14:17PM +0930, Rusty Russell wrote:
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
So my plan was to tie this assumption to the new PCI layout.
I don't object but old qemu has this limitation for s390 as well,
and that's not using PCI, right? So how do we detect
new hypervisor there?
--
MST
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2012-10-08 20:29:33
On Thu, Oct 04, 2012 at 01:04:56PM +0930, Rusty Russell wrote:
Anthony Liguori [off-list ref] writes:
quoted
Rusty Russell [off-list ref] writes:
quoted
"Michael S. Tsirkin" [off-list ref] writes:
quoted
Thinking about Sasha's patches, we can reduce ring usage
for virtio net small packets dramatically if we put
virtio net header inline with the data.
This can be done for free in case guest net stack allocated
extra head room for the packet, and I don't see
why would this have any downsides.
I've been wanting to do this for the longest time... but...
quoted
Even though with my recent patches qemu
no longer requires header to be the first s/g element,
we need a new feature bit to detect this.
A trivial qemu patch will be sent separately.
There's a reason I haven't done this. I really, really dislike "my
implemention isn't broken" feature bits. We could have an infinite
number of them, for each bug in each device.
This is a bug in the specification.
The QEMU implementation pre-dates the specification. All of the actual
implementations of virtio relied on the semantics of s/g elements and
still do.
lguest fix is pending in my queue. lkvm and qemu are broken; lkvm isn't
ever going to be merged, so I'm not sure what its status is? But I'm
determined to fix qemu, and hence my torture patch to make sure this
doesn't creep in again.
If you look at my patch you'll notice there's also a
comment in virtio_net.h that seems to be broken in this respect:
/* This is the first element of the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header. */
There is a similar comment in virtio-blk.