diff mbox

[14/15] hw/block/virtio-blk: create num_queues vqs if dataplane is enabled

Message ID 1406720388-18671-15-git-send-email-ming.lei@canonical.com
State New
Headers show

Commit Message

Ming Lei July 30, 2014, 11:39 a.m. UTC
Now we only support multi vqs for dataplane case.

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 hw/block/virtio-blk.c          |   18 +++++++++++++++++-
 include/hw/virtio/virtio-blk.h |    1 +
 2 files changed, 18 insertions(+), 1 deletion(-)

Comments

Paolo Bonzini July 30, 2014, 2:01 p.m. UTC | #1
Il 30/07/2014 13:39, Ming Lei ha scritto:
> Now we only support multi vqs for dataplane case.
> 
> Signed-off-by: Ming Lei <ming.lei@canonical.com>
> ---
>  hw/block/virtio-blk.c          |   18 +++++++++++++++++-
>  include/hw/virtio/virtio-blk.h |    1 +
>  2 files changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index ab99156..44e9956 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -556,6 +556,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
>      blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
>      blkcfg.alignment_offset = 0;
>      blkcfg.wce = bdrv_enable_write_cache(s->bs);
> +    stw_p(&blkcfg.num_queues, s->blk.num_queues);
>      memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
>  }
>  
> @@ -590,6 +591,12 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
>      if (bdrv_is_read_only(s->bs))
>          features |= 1 << VIRTIO_BLK_F_RO;
>  
> +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
> +    if (s->blk.num_queues > 1) {
> +        features |= 1 << VIRTIO_BLK_F_MQ;
> +    }
> +#endif
> +
>      return features;
>  }
>  
> @@ -739,8 +746,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
>  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
>      Error *err = NULL;
>  #endif
> +    int i;
>      static int virtio_blk_id;
>  
> +#ifndef CONFIG_VIRTIO_BLK_DATA_PLANE
> +    blk->num_queues = 1;
> +#endif
> +
>      if (!blk->conf.bs) {
>          error_setg(errp, "drive property not set");
>          return;
> @@ -765,7 +777,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
>      s->rq = NULL;
>      s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
>  
> -    s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
> +    s->vqs = g_malloc0(sizeof(VirtQueue *) * blk->num_queues);
> +    for (i = 0; i < blk->num_queues; i++)
> +        s->vqs[i] = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
> +    s->vq = s->vqs[0];
>      s->complete_request = virtio_blk_complete_request;
>  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
>      virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
> @@ -802,6 +817,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
>      qemu_del_vm_change_state_handler(s->change);
>      unregister_savevm(dev, "virtio-blk", s);
>      blockdev_mark_auto_del(s->bs);
> +    g_free(s->vqs);
>      virtio_cleanup(vdev);
>  }
>  
> diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
> index ad70c9a..b4609dd 100644
> --- a/include/hw/virtio/virtio-blk.h
> +++ b/include/hw/virtio/virtio-blk.h
> @@ -132,6 +132,7 @@ typedef struct VirtIOBlock {
>      VirtIODevice parent_obj;
>      BlockDriverState *bs;
>      VirtQueue *vq;
> +    VirtQueue **vqs;
>      void *rq;
>      QEMUBH *bh;
>      BlockConf *conf;
> 

Dataplane must not be a change to the guest ABI.  If you implement this
feature you have to implement it for both dataplane and non-dataplne.

Paolo
Michael S. Tsirkin July 30, 2014, 3:12 p.m. UTC | #2
On Wed, Jul 30, 2014 at 04:01:59PM +0200, Paolo Bonzini wrote:
> Il 30/07/2014 13:39, Ming Lei ha scritto:
> > Now we only support multi vqs for dataplane case.
> > 
> > Signed-off-by: Ming Lei <ming.lei@canonical.com>
> > ---
> >  hw/block/virtio-blk.c          |   18 +++++++++++++++++-
> >  include/hw/virtio/virtio-blk.h |    1 +
> >  2 files changed, 18 insertions(+), 1 deletion(-)
> > 
> > diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> > index ab99156..44e9956 100644
> > --- a/hw/block/virtio-blk.c
> > +++ b/hw/block/virtio-blk.c
> > @@ -556,6 +556,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
> >      blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
> >      blkcfg.alignment_offset = 0;
> >      blkcfg.wce = bdrv_enable_write_cache(s->bs);
> > +    stw_p(&blkcfg.num_queues, s->blk.num_queues);
> >      memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
> >  }
> >  
> > @@ -590,6 +591,12 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
> >      if (bdrv_is_read_only(s->bs))
> >          features |= 1 << VIRTIO_BLK_F_RO;
> >  
> > +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
> > +    if (s->blk.num_queues > 1) {
> > +        features |= 1 << VIRTIO_BLK_F_MQ;
> > +    }
> > +#endif
> > +
> >      return features;
> >  }
> >  
> > @@ -739,8 +746,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
> >  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
> >      Error *err = NULL;
> >  #endif
> > +    int i;
> >      static int virtio_blk_id;
> >  
> > +#ifndef CONFIG_VIRTIO_BLK_DATA_PLANE
> > +    blk->num_queues = 1;
> > +#endif
> > +
> >      if (!blk->conf.bs) {
> >          error_setg(errp, "drive property not set");
> >          return;
> > @@ -765,7 +777,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
> >      s->rq = NULL;
> >      s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
> >  
> > -    s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
> > +    s->vqs = g_malloc0(sizeof(VirtQueue *) * blk->num_queues);
> > +    for (i = 0; i < blk->num_queues; i++)
> > +        s->vqs[i] = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
> > +    s->vq = s->vqs[0];
> >      s->complete_request = virtio_blk_complete_request;
> >  #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
> >      virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
> > @@ -802,6 +817,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
> >      qemu_del_vm_change_state_handler(s->change);
> >      unregister_savevm(dev, "virtio-blk", s);
> >      blockdev_mark_auto_del(s->bs);
> > +    g_free(s->vqs);
> >      virtio_cleanup(vdev);
> >  }
> >  
> > diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
> > index ad70c9a..b4609dd 100644
> > --- a/include/hw/virtio/virtio-blk.h
> > +++ b/include/hw/virtio/virtio-blk.h
> > @@ -132,6 +132,7 @@ typedef struct VirtIOBlock {
> >      VirtIODevice parent_obj;
> >      BlockDriverState *bs;
> >      VirtQueue *vq;
> > +    VirtQueue **vqs;
> >      void *rq;
> >      QEMUBH *bh;
> >      BlockConf *conf;
> > 
> 
> Dataplane must not be a change to the guest ABI.  If you implement this
> feature you have to implement it for both dataplane and non-dataplne.
> 
> Paolo

Actually, I think different backends at runtime should be allowed to
change guest visible ABI.  For example if you give qemu a read only
backend this is guest visible right?

However relying on ifdefs is wrong.
It should be a runtime thing.
Paolo Bonzini July 30, 2014, 3:25 p.m. UTC | #3
Il 30/07/2014 17:12, Michael S. Tsirkin ha scritto:
>> > 
>> > Dataplane must not be a change to the guest ABI.  If you implement this
>> > feature you have to implement it for both dataplane and non-dataplne.
>> > 
>> > Paolo
> Actually, I think different backends at runtime should be allowed to
> change guest visible ABI.  For example if you give qemu a read only
> backend this is guest visible right?

Dataplane is not meant to be a different backend, it's just moving stuff
out to a separate thread.  It's only due to QEMU limitation that it
doesn't share the vring code (and these patches include a lot of steps
backwards where dataplane becomes != non-dataplane).

Paolo
Ming Lei July 31, 2014, 3:47 a.m. UTC | #4
On Wed, Jul 30, 2014 at 11:25 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 30/07/2014 17:12, Michael S. Tsirkin ha scritto:
>>> >
>>> > Dataplane must not be a change to the guest ABI.  If you implement this
>>> > feature you have to implement it for both dataplane and non-dataplne.
>>> >

IMO, no matter if the feature is set or not, both old and new VM
can support it well.

Per virtio spec, only the feature is set, the VM can be allowed to
access the 'num_queues' field, and I didn't see any problem from
VM's view point.

So could you explain why both dataplane and non-dataplane have
to support the feature.

I am doing so because there isn't performance advantage to take mq
for non-dataplane.

>>> > Paolo
>> Actually, I think different backends at runtime should be allowed to
>> change guest visible ABI.  For example if you give qemu a read only
>> backend this is guest visible right?
>
> Dataplane is not meant to be a different backend, it's just moving stuff
> out to a separate thread.  It's only due to QEMU limitation that it
> doesn't share the vring code (and these patches include a lot of steps
> backwards where dataplane becomes != non-dataplane).

There won't lots of backwards steps, just the bypass co patch, which
is just bypassing co in case of being unnecessary for raw image case,
but it is still one code path.

As I mentioned, all these steps are just for the performance
regression from the commit 580b6b2aa2(dataplane: use the
QEMU block layer for I/O).

Thanks,
Paolo Bonzini July 31, 2014, 8:52 a.m. UTC | #5
Il 31/07/2014 05:47, Ming Lei ha scritto:
> On Wed, Jul 30, 2014 at 11:25 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 30/07/2014 17:12, Michael S. Tsirkin ha scritto:
>>>>>
>>>>> Dataplane must not be a change to the guest ABI.  If you implement this
>>>>> feature you have to implement it for both dataplane and non-dataplne.
>>>>>
> 
> IMO, no matter if the feature is set or not, both old and new VM
> can support it well.
> 
> Per virtio spec, only the feature is set, the VM can be allowed to
> access the 'num_queues' field, and I didn't see any problem from
> VM's view point.
> 
> So could you explain why both dataplane and non-dataplane have
> to support the feature.

Because otherwise you change the guest ABI.

> I am doing so because there isn't performance advantage to take mq
> for non-dataplane.

It doesn't matter, changing features between dataplane and non-dataplane
is not something that you can do.

>>> Actually, I think different backends at runtime should be allowed to
>>> change guest visible ABI.  For example if you give qemu a read only
>>> backend this is guest visible right?
>>
>> Dataplane is not meant to be a different backend, it's just moving stuff
>> out to a separate thread.  It's only due to QEMU limitation that it
>> doesn't share the vring code (and these patches include a lot of steps
>> backwards where dataplane becomes != non-dataplane).
> 
> There won't lots of backwards steps, just the bypass co patch, which
> is just bypassing co in case of being unnecessary for raw image case,
> but it is still one code path.

Using the object pool for dataplane only is a backwards step,
implementing multique for dataplane only is a backwards step, bypassing
coroutines for dataplane only is a backwards step.

Paolo
Ming Lei Aug. 1, 2014, 3:09 a.m. UTC | #6
On Thu, Jul 31, 2014 at 4:52 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 31/07/2014 05:47, Ming Lei ha scritto:
>> On Wed, Jul 30, 2014 at 11:25 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> Il 30/07/2014 17:12, Michael S. Tsirkin ha scritto:
>>>>>>
>>>>>> Dataplane must not be a change to the guest ABI.  If you implement this
>>>>>> feature you have to implement it for both dataplane and non-dataplne.
>>>>>>
>>
>> IMO, no matter if the feature is set or not, both old and new VM
>> can support it well.
>>
>> Per virtio spec, only the feature is set, the VM can be allowed to
>> access the 'num_queues' field, and I didn't see any problem from
>> VM's view point.
>>
>> So could you explain why both dataplane and non-dataplane have
>> to support the feature.
>
> Because otherwise you change the guest ABI.

Sorry, I don't understand why the guest ABI is changed since
VM only parses 'num_queues' iff the feature is set, and the DATAPLANE
macro is determined during compiling.

>
>> I am doing so because there isn't performance advantage to take mq
>> for non-dataplane.
>
> It doesn't matter, changing features between dataplane and non-dataplane
> is not something that you can do.

Actually it is easy to support multi virtqueue for non-dataplane,
and it should be enough to remove two 'ifdef'.

>
>>>> Actually, I think different backends at runtime should be allowed to
>>>> change guest visible ABI.  For example if you give qemu a read only
>>>> backend this is guest visible right?
>>>
>>> Dataplane is not meant to be a different backend, it's just moving stuff
>>> out to a separate thread.  It's only due to QEMU limitation that it
>>> doesn't share the vring code (and these patches include a lot of steps
>>> backwards where dataplane becomes != non-dataplane).
>>
>> There won't lots of backwards steps, just the bypass co patch, which
>> is just bypassing co in case of being unnecessary for raw image case,
>> but it is still one code path.
>
> Using the object pool for dataplane only is a backwards step,
> implementing multique for dataplane only is a backwards step,

This one isn't since no multique has been tried before for virtio-blk, :-)

> bypassing
> coroutines for dataplane only is a backwards step.

OK, then all these backwards are positive steps too since they
do improve performance, :-)

The only side-effect I thought of is that bypassing coroutine may
cause block layer a bit complicated.

Thanks,
Ming Lei Aug. 1, 2014, 3:24 a.m. UTC | #7
On Fri, Aug 1, 2014 at 11:09 AM, Ming Lei <ming.lei@canonical.com> wrote:
> On Thu, Jul 31, 2014 at 4:52 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:

>>
>> It doesn't matter, changing features between dataplane and non-dataplane
>> is not something that you can do.
>
> Actually it is easy to support multi virtqueue for non-dataplane,
> and it should be enough to remove two 'ifdef'.

Sorry, virtqueue_pop()/virtqueue_push() need changes too, but it
won't be difficult too since 'qid' has been introduced inside
VirtIOBlockReq already.

Thanks,
Paolo Bonzini Aug. 1, 2014, 6:10 a.m. UTC | #8
Il 01/08/2014 05:09, Ming Lei ha scritto:
>>> >> Per virtio spec, only the feature is set, the VM can be allowed to
>>> >> access the 'num_queues' field, and I didn't see any problem from
>>> >> VM's view point.
>>> >>
>>> >> So could you explain why both dataplane and non-dataplane have
>>> >> to support the feature.
>> >
>> > Because otherwise you change the guest ABI.
> Sorry, I don't understand why the guest ABI is changed since
> VM only parses 'num_queues' iff the feature is set, and the DATAPLANE
> macro is determined during compiling.

Even recompiling the same version of QEMU should not change the guest
ABI.  Recompilation may affect which devices are present, but then the
migration destination will not even start if something is broken.

And as you pointed out, migration from dataplane to non-dataplane will
break because you didn't convert callers of virtqueue_pop/push.

Paolo
Ming Lei Aug. 1, 2014, 7:35 a.m. UTC | #9
On Fri, Aug 1, 2014 at 2:10 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 01/08/2014 05:09, Ming Lei ha scritto:
>>>> >> Per virtio spec, only the feature is set, the VM can be allowed to
>>>> >> access the 'num_queues' field, and I didn't see any problem from
>>>> >> VM's view point.
>>>> >>
>>>> >> So could you explain why both dataplane and non-dataplane have
>>>> >> to support the feature.
>>> >
>>> > Because otherwise you change the guest ABI.
>> Sorry, I don't understand why the guest ABI is changed since
>> VM only parses 'num_queues' iff the feature is set, and the DATAPLANE
>> macro is determined during compiling.
>
> Even recompiling the same version of QEMU should not change the guest
> ABI.  Recompilation may affect which devices are present, but then the
> migration destination will not even start if something is broken.
>
> And as you pointed out, migration from dataplane to non-dataplane will
> break because you didn't convert callers of virtqueue_pop/push.

OK, I will convert non-dataplane to support multi virtqueues in V1,
and the conversion is not difficult and straightforward.

BTW, docs/migration.txt mentions that "QEMU has to be launched
with the same arguments the two times", so can I understand that
migration from dataplane to non-dataplane shouldn't have been
allowed?

Thanks,
Paolo Bonzini Aug. 1, 2014, 7:46 a.m. UTC | #10
Il 01/08/2014 09:35, Ming Lei ha scritto:
> OK, I will convert non-dataplane to support multi virtqueues in V1,
> and the conversion is not difficult and straightforward.
> 
> BTW, docs/migration.txt mentions that "QEMU has to be launched
> with the same arguments the two times", so can I understand that
> migration from dataplane to non-dataplane shouldn't have been
> allowed?

You're right, that text gives a rule of thumb but it is not absolutely true.

It is for example obviously okay to have different paths for drives in
the two invocations.  It is also okay to use different formats (raw vs.
qcow2) if, for example, you are migrating disk contents (either with
"migrate -b" or with the embedded NBD server).

Dataplane is another such case where an option does not affect how the
device behaves.  It is a bit more clearer if you think of it as just
"use an iothread different from the default one", which is what we're
aiming at.  Everything else is working around limitations in QEMU, and
will disappear once these limitations are lifted.

Paolo
diff mbox

Patch

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index ab99156..44e9956 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -556,6 +556,7 @@  static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
     blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
     blkcfg.alignment_offset = 0;
     blkcfg.wce = bdrv_enable_write_cache(s->bs);
+    stw_p(&blkcfg.num_queues, s->blk.num_queues);
     memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
 }
 
@@ -590,6 +591,12 @@  static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
     if (bdrv_is_read_only(s->bs))
         features |= 1 << VIRTIO_BLK_F_RO;
 
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    if (s->blk.num_queues > 1) {
+        features |= 1 << VIRTIO_BLK_F_MQ;
+    }
+#endif
+
     return features;
 }
 
@@ -739,8 +746,13 @@  static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     Error *err = NULL;
 #endif
+    int i;
     static int virtio_blk_id;
 
+#ifndef CONFIG_VIRTIO_BLK_DATA_PLANE
+    blk->num_queues = 1;
+#endif
+
     if (!blk->conf.bs) {
         error_setg(errp, "drive property not set");
         return;
@@ -765,7 +777,10 @@  static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
     s->rq = NULL;
     s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
 
-    s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
+    s->vqs = g_malloc0(sizeof(VirtQueue *) * blk->num_queues);
+    for (i = 0; i < blk->num_queues; i++)
+        s->vqs[i] = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
+    s->vq = s->vqs[0];
     s->complete_request = virtio_blk_complete_request;
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
@@ -802,6 +817,7 @@  static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
     qemu_del_vm_change_state_handler(s->change);
     unregister_savevm(dev, "virtio-blk", s);
     blockdev_mark_auto_del(s->bs);
+    g_free(s->vqs);
     virtio_cleanup(vdev);
 }
 
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index ad70c9a..b4609dd 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -132,6 +132,7 @@  typedef struct VirtIOBlock {
     VirtIODevice parent_obj;
     BlockDriverState *bs;
     VirtQueue *vq;
+    VirtQueue **vqs;
     void *rq;
     QEMUBH *bh;
     BlockConf *conf;