Re: [PATCH v7 08/12] vdpa: Move command buffers map to start of net device

2022-08-09 Thread Jason Wang
On Tue, Aug 9, 2022 at 4:04 PM Eugenio Perez Martin  wrote:
>
> On Tue, Aug 9, 2022 at 9:49 AM Jason Wang  wrote:
> >
> > On Tue, Aug 9, 2022 at 3:34 PM Eugenio Perez Martin  
> > wrote:
> > >
> > > On Tue, Aug 9, 2022 at 9:04 AM Jason Wang  wrote:
> > > >
> > > > On Fri, Aug 5, 2022 at 2:29 AM Eugenio Pérez  
> > > > wrote:
> > > > >
> > > > > As this series will reuse them to restore the device state at the end 
> > > > > of
> > > > > a migration (or a device start), let's allocate only once at the 
> > > > > device
> > > > > start so we don't duplicate their map and unmap.
> > > > >
> > > > > Signed-off-by: Eugenio Pérez 
> > > > > ---
> > > > >  net/vhost-vdpa.c | 123 
> > > > > ++-
> > > > >  1 file changed, 58 insertions(+), 65 deletions(-)
> > > > >
> > > > > diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> > > > > index 55e8a39a56..2c6a26cca0 100644
> > > > > --- a/net/vhost-vdpa.c
> > > > > +++ b/net/vhost-vdpa.c
> > > > > @@ -263,29 +263,20 @@ static size_t 
> > > > > vhost_vdpa_net_cvq_cmd_page_len(void)
> > > > >  return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), 
> > > > > qemu_real_host_page_size());
> > > > >  }
> > > > >
> > > > > -/** Copy and map a guest buffer. */
> > > > > -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
> > > > > -   const struct iovec *out_data,
> > > > > -   size_t out_num, size_t data_len, 
> > > > > void *buf,
> > > > > -   size_t *written, bool write)
> > > > > +/** Map CVQ buffer. */
> > > > > +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, 
> > > > > size_t size,
> > > > > +  bool write)
> > > > >  {
> > > > >  DMAMap map = {};
> > > > >  int r;
> > > > >
> > > > > -if (unlikely(!data_len)) {
> > > > > -qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s 
> > > > > buffer\n",
> > > > > -  __func__, write ? "in" : "out");
> > > > > -return false;
> > > > > -}
> > > > > -
> > > > > -*written = iov_to_buf(out_data, out_num, 0, buf, data_len);
> > > > >  map.translated_addr = (hwaddr)(uintptr_t)buf;
> > > > > -map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
> > > > > +map.size = size - 1;
> > > >
> > > > Just noticed this, I think I've asked for the reason before but I
> > > > don't remember the answer.
> > > >
> > > > But it looks like a hint of a defect of the current API design.
> > > >
> > >
> > > I can look for it in the mail list, but long story short:
> > > vDPA DMA API is *not* inclusive: To map the first page, you map (.iova
> > > = 0, .size = 4096).
> > > IOVA tree API has been inclusive forever: To map the first page, you
> > > map (.iova = 0, .size = 4095). If we map with .size = 4096, .iova =
> > > 4096 is considered mapped too.
> >
> > This looks like a bug.
> >
> > {.iova=0, size=0} should be illegal but if I understand you correctly,
> > it means [0, 1)?
> >
>
> On iova_tree it works the way you point here, yes. Maybe the member's
> name should have been length or something like that.
>
> On intel_iommu the address *mask* is actually used to fill the size,
> not the actual DMA entry length.
>
> For SVQ I think it would be beneficial to declare two different types,
> size_inclusive and size_non_inclusive, and check at compile time if
> the caller is using the right type.

That's sub-optimal, we'd better go with a single type of size or
switch to use [start, end].

> But it's not top priority at the
> moment.

Yes, let's optimize it on top.

Thanks

>
> Thanks!
>
> > Thanks
> >
> > >
> > > To adapt one to the other would have been an API change even before
> > > the introduction of vhost-iova-tree.
> > >
> > > Thanks!
> > >
> > >
> > > > Thanks
> > > >
> > > > >  map.perm = write ? IOMMU_RW : IOMMU_RO,
> > > > >  r = vhost_iova_tree_map_alloc(v->iova_tree, );
> > > > >  if (unlikely(r != IOVA_OK)) {
> > > > >  error_report("Cannot map injected element");
> > > > > -return false;
> > > > > +return r;
> > > > >  }
> > > > >
> > > > >  r = vhost_vdpa_dma_map(v, map.iova, 
> > > > > vhost_vdpa_net_cvq_cmd_page_len(), buf,
> > > > > @@ -294,50 +285,58 @@ static bool vhost_vdpa_cvq_map_buf(struct 
> > > > > vhost_vdpa *v,
> > > > >  goto dma_map_err;
> > > > >  }
> > > > >
> > > > > -return true;
> > > > > +return 0;
> > > > >
> > > > >  dma_map_err:
> > > > >  vhost_iova_tree_remove(v->iova_tree, );
> > > > > -return false;
> > > > > +return r;
> > > > >  }
> > > > >
> > > > > -/**
> > > > > - * Copy the guest element into a dedicated buffer suitable to be 
> > > > > sent to NIC
> > > > > - *
> > > > > - * @iov: [0] is the out buffer, [1] is the in one
> > > > > - */
> > > > > -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
> > > > > -VirtQueueElement *elem,

Re: [PATCH v7 08/12] vdpa: Move command buffers map to start of net device

2022-08-09 Thread Eugenio Perez Martin
On Tue, Aug 9, 2022 at 9:49 AM Jason Wang  wrote:
>
> On Tue, Aug 9, 2022 at 3:34 PM Eugenio Perez Martin  
> wrote:
> >
> > On Tue, Aug 9, 2022 at 9:04 AM Jason Wang  wrote:
> > >
> > > On Fri, Aug 5, 2022 at 2:29 AM Eugenio Pérez  wrote:
> > > >
> > > > As this series will reuse them to restore the device state at the end of
> > > > a migration (or a device start), let's allocate only once at the device
> > > > start so we don't duplicate their map and unmap.
> > > >
> > > > Signed-off-by: Eugenio Pérez 
> > > > ---
> > > >  net/vhost-vdpa.c | 123 ++-
> > > >  1 file changed, 58 insertions(+), 65 deletions(-)
> > > >
> > > > diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> > > > index 55e8a39a56..2c6a26cca0 100644
> > > > --- a/net/vhost-vdpa.c
> > > > +++ b/net/vhost-vdpa.c
> > > > @@ -263,29 +263,20 @@ static size_t 
> > > > vhost_vdpa_net_cvq_cmd_page_len(void)
> > > >  return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), 
> > > > qemu_real_host_page_size());
> > > >  }
> > > >
> > > > -/** Copy and map a guest buffer. */
> > > > -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
> > > > -   const struct iovec *out_data,
> > > > -   size_t out_num, size_t data_len, 
> > > > void *buf,
> > > > -   size_t *written, bool write)
> > > > +/** Map CVQ buffer. */
> > > > +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, 
> > > > size_t size,
> > > > +  bool write)
> > > >  {
> > > >  DMAMap map = {};
> > > >  int r;
> > > >
> > > > -if (unlikely(!data_len)) {
> > > > -qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s 
> > > > buffer\n",
> > > > -  __func__, write ? "in" : "out");
> > > > -return false;
> > > > -}
> > > > -
> > > > -*written = iov_to_buf(out_data, out_num, 0, buf, data_len);
> > > >  map.translated_addr = (hwaddr)(uintptr_t)buf;
> > > > -map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
> > > > +map.size = size - 1;
> > >
> > > Just noticed this, I think I've asked for the reason before but I
> > > don't remember the answer.
> > >
> > > But it looks like a hint of a defect of the current API design.
> > >
> >
> > I can look for it in the mail list, but long story short:
> > vDPA DMA API is *not* inclusive: To map the first page, you map (.iova
> > = 0, .size = 4096).
> > IOVA tree API has been inclusive forever: To map the first page, you
> > map (.iova = 0, .size = 4095). If we map with .size = 4096, .iova =
> > 4096 is considered mapped too.
>
> This looks like a bug.
>
> {.iova=0, size=0} should be illegal but if I understand you correctly,
> it means [0, 1)?
>

On iova_tree it works the way you point here, yes. Maybe the member's
name should have been length or something like that.

On intel_iommu the address *mask* is actually used to fill the size,
not the actual DMA entry length.

For SVQ I think it would be beneficial to declare two different types,
size_inclusive and size_non_inclusive, and check at compile time if
the caller is using the right type. But it's not top priority at the
moment.

Thanks!

> Thanks
>
> >
> > To adapt one to the other would have been an API change even before
> > the introduction of vhost-iova-tree.
> >
> > Thanks!
> >
> >
> > > Thanks
> > >
> > > >  map.perm = write ? IOMMU_RW : IOMMU_RO,
> > > >  r = vhost_iova_tree_map_alloc(v->iova_tree, );
> > > >  if (unlikely(r != IOVA_OK)) {
> > > >  error_report("Cannot map injected element");
> > > > -return false;
> > > > +return r;
> > > >  }
> > > >
> > > >  r = vhost_vdpa_dma_map(v, map.iova, 
> > > > vhost_vdpa_net_cvq_cmd_page_len(), buf,
> > > > @@ -294,50 +285,58 @@ static bool vhost_vdpa_cvq_map_buf(struct 
> > > > vhost_vdpa *v,
> > > >  goto dma_map_err;
> > > >  }
> > > >
> > > > -return true;
> > > > +return 0;
> > > >
> > > >  dma_map_err:
> > > >  vhost_iova_tree_remove(v->iova_tree, );
> > > > -return false;
> > > > +return r;
> > > >  }
> > > >
> > > > -/**
> > > > - * Copy the guest element into a dedicated buffer suitable to be sent 
> > > > to NIC
> > > > - *
> > > > - * @iov: [0] is the out buffer, [1] is the in one
> > > > - */
> > > > -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
> > > > -VirtQueueElement *elem,
> > > > -struct iovec *iov)
> > > > +static int vhost_vdpa_net_cvq_prepare(NetClientState *nc)
> > > >  {
> > > > -size_t in_copied;
> > > > -bool ok;
> > > > +VhostVDPAState *s;
> > > > +int r;
> > > >
> > > > -iov[0].iov_base = s->cvq_cmd_out_buffer;
> > > > -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, elem->out_sg, 
> > > > elem->out_num,
> > > > -vhost_vdpa_net_cvq_cmd_len(), 
> > > > 

Re: [PATCH v7 08/12] vdpa: Move command buffers map to start of net device

2022-08-09 Thread Jason Wang
On Tue, Aug 9, 2022 at 3:34 PM Eugenio Perez Martin  wrote:
>
> On Tue, Aug 9, 2022 at 9:04 AM Jason Wang  wrote:
> >
> > On Fri, Aug 5, 2022 at 2:29 AM Eugenio Pérez  wrote:
> > >
> > > As this series will reuse them to restore the device state at the end of
> > > a migration (or a device start), let's allocate only once at the device
> > > start so we don't duplicate their map and unmap.
> > >
> > > Signed-off-by: Eugenio Pérez 
> > > ---
> > >  net/vhost-vdpa.c | 123 ++-
> > >  1 file changed, 58 insertions(+), 65 deletions(-)
> > >
> > > diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> > > index 55e8a39a56..2c6a26cca0 100644
> > > --- a/net/vhost-vdpa.c
> > > +++ b/net/vhost-vdpa.c
> > > @@ -263,29 +263,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void)
> > >  return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), 
> > > qemu_real_host_page_size());
> > >  }
> > >
> > > -/** Copy and map a guest buffer. */
> > > -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
> > > -   const struct iovec *out_data,
> > > -   size_t out_num, size_t data_len, void 
> > > *buf,
> > > -   size_t *written, bool write)
> > > +/** Map CVQ buffer. */
> > > +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, 
> > > size_t size,
> > > +  bool write)
> > >  {
> > >  DMAMap map = {};
> > >  int r;
> > >
> > > -if (unlikely(!data_len)) {
> > > -qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s 
> > > buffer\n",
> > > -  __func__, write ? "in" : "out");
> > > -return false;
> > > -}
> > > -
> > > -*written = iov_to_buf(out_data, out_num, 0, buf, data_len);
> > >  map.translated_addr = (hwaddr)(uintptr_t)buf;
> > > -map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
> > > +map.size = size - 1;
> >
> > Just noticed this, I think I've asked for the reason before but I
> > don't remember the answer.
> >
> > But it looks like a hint of a defect of the current API design.
> >
>
> I can look for it in the mail list, but long story short:
> vDPA DMA API is *not* inclusive: To map the first page, you map (.iova
> = 0, .size = 4096).
> IOVA tree API has been inclusive forever: To map the first page, you
> map (.iova = 0, .size = 4095). If we map with .size = 4096, .iova =
> 4096 is considered mapped too.

This looks like a bug.

{.iova=0, size=0} should be illegal but if I understand you correctly,
it means [0, 1)?

Thanks

>
> To adapt one to the other would have been an API change even before
> the introduction of vhost-iova-tree.
>
> Thanks!
>
>
> > Thanks
> >
> > >  map.perm = write ? IOMMU_RW : IOMMU_RO,
> > >  r = vhost_iova_tree_map_alloc(v->iova_tree, );
> > >  if (unlikely(r != IOVA_OK)) {
> > >  error_report("Cannot map injected element");
> > > -return false;
> > > +return r;
> > >  }
> > >
> > >  r = vhost_vdpa_dma_map(v, map.iova, 
> > > vhost_vdpa_net_cvq_cmd_page_len(), buf,
> > > @@ -294,50 +285,58 @@ static bool vhost_vdpa_cvq_map_buf(struct 
> > > vhost_vdpa *v,
> > >  goto dma_map_err;
> > >  }
> > >
> > > -return true;
> > > +return 0;
> > >
> > >  dma_map_err:
> > >  vhost_iova_tree_remove(v->iova_tree, );
> > > -return false;
> > > +return r;
> > >  }
> > >
> > > -/**
> > > - * Copy the guest element into a dedicated buffer suitable to be sent to 
> > > NIC
> > > - *
> > > - * @iov: [0] is the out buffer, [1] is the in one
> > > - */
> > > -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
> > > -VirtQueueElement *elem,
> > > -struct iovec *iov)
> > > +static int vhost_vdpa_net_cvq_prepare(NetClientState *nc)
> > >  {
> > > -size_t in_copied;
> > > -bool ok;
> > > +VhostVDPAState *s;
> > > +int r;
> > >
> > > -iov[0].iov_base = s->cvq_cmd_out_buffer;
> > > -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, elem->out_sg, 
> > > elem->out_num,
> > > -vhost_vdpa_net_cvq_cmd_len(), 
> > > iov[0].iov_base,
> > > -[0].iov_len, false);
> > > -if (unlikely(!ok)) {
> > > -return false;
> > > +assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
> > > +
> > > +s = DO_UPCAST(VhostVDPAState, nc, nc);
> > > +if (!s->vhost_vdpa.shadow_vqs_enabled) {
> > > +return 0;
> > >  }
> > >
> > > -iov[1].iov_base = s->cvq_cmd_in_buffer;
> > > -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, NULL, 0,
> > > -sizeof(virtio_net_ctrl_ack), 
> > > iov[1].iov_base,
> > > -_copied, true);
> > > -if (unlikely(!ok)) {
> > > +r = vhost_vdpa_cvq_map_buf(>vhost_vdpa, s->cvq_cmd_out_buffer,
> > > +   

Re: [PATCH v7 08/12] vdpa: Move command buffers map to start of net device

2022-08-09 Thread Eugenio Perez Martin
On Tue, Aug 9, 2022 at 9:04 AM Jason Wang  wrote:
>
> On Fri, Aug 5, 2022 at 2:29 AM Eugenio Pérez  wrote:
> >
> > As this series will reuse them to restore the device state at the end of
> > a migration (or a device start), let's allocate only once at the device
> > start so we don't duplicate their map and unmap.
> >
> > Signed-off-by: Eugenio Pérez 
> > ---
> >  net/vhost-vdpa.c | 123 ++-
> >  1 file changed, 58 insertions(+), 65 deletions(-)
> >
> > diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> > index 55e8a39a56..2c6a26cca0 100644
> > --- a/net/vhost-vdpa.c
> > +++ b/net/vhost-vdpa.c
> > @@ -263,29 +263,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void)
> >  return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), 
> > qemu_real_host_page_size());
> >  }
> >
> > -/** Copy and map a guest buffer. */
> > -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
> > -   const struct iovec *out_data,
> > -   size_t out_num, size_t data_len, void 
> > *buf,
> > -   size_t *written, bool write)
> > +/** Map CVQ buffer. */
> > +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t 
> > size,
> > +  bool write)
> >  {
> >  DMAMap map = {};
> >  int r;
> >
> > -if (unlikely(!data_len)) {
> > -qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n",
> > -  __func__, write ? "in" : "out");
> > -return false;
> > -}
> > -
> > -*written = iov_to_buf(out_data, out_num, 0, buf, data_len);
> >  map.translated_addr = (hwaddr)(uintptr_t)buf;
> > -map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
> > +map.size = size - 1;
>
> Just noticed this, I think I've asked for the reason before but I
> don't remember the answer.
>
> But it looks like a hint of a defect of the current API design.
>

I can look for it in the mail list, but long story short:
vDPA DMA API is *not* inclusive: To map the first page, you map (.iova
= 0, .size = 4096).
IOVA tree API has been inclusive forever: To map the first page, you
map (.iova = 0, .size = 4095). If we map with .size = 4096, .iova =
4096 is considered mapped too.

To adapt one to the other would have been an API change even before
the introduction of vhost-iova-tree.

Thanks!


> Thanks
>
> >  map.perm = write ? IOMMU_RW : IOMMU_RO,
> >  r = vhost_iova_tree_map_alloc(v->iova_tree, );
> >  if (unlikely(r != IOVA_OK)) {
> >  error_report("Cannot map injected element");
> > -return false;
> > +return r;
> >  }
> >
> >  r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), 
> > buf,
> > @@ -294,50 +285,58 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa 
> > *v,
> >  goto dma_map_err;
> >  }
> >
> > -return true;
> > +return 0;
> >
> >  dma_map_err:
> >  vhost_iova_tree_remove(v->iova_tree, );
> > -return false;
> > +return r;
> >  }
> >
> > -/**
> > - * Copy the guest element into a dedicated buffer suitable to be sent to 
> > NIC
> > - *
> > - * @iov: [0] is the out buffer, [1] is the in one
> > - */
> > -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
> > -VirtQueueElement *elem,
> > -struct iovec *iov)
> > +static int vhost_vdpa_net_cvq_prepare(NetClientState *nc)
> >  {
> > -size_t in_copied;
> > -bool ok;
> > +VhostVDPAState *s;
> > +int r;
> >
> > -iov[0].iov_base = s->cvq_cmd_out_buffer;
> > -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, elem->out_sg, 
> > elem->out_num,
> > -vhost_vdpa_net_cvq_cmd_len(), 
> > iov[0].iov_base,
> > -[0].iov_len, false);
> > -if (unlikely(!ok)) {
> > -return false;
> > +assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
> > +
> > +s = DO_UPCAST(VhostVDPAState, nc, nc);
> > +if (!s->vhost_vdpa.shadow_vqs_enabled) {
> > +return 0;
> >  }
> >
> > -iov[1].iov_base = s->cvq_cmd_in_buffer;
> > -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, NULL, 0,
> > -sizeof(virtio_net_ctrl_ack), 
> > iov[1].iov_base,
> > -_copied, true);
> > -if (unlikely(!ok)) {
> > +r = vhost_vdpa_cvq_map_buf(>vhost_vdpa, s->cvq_cmd_out_buffer,
> > +   vhost_vdpa_net_cvq_cmd_page_len(), false);
> > +if (unlikely(r < 0)) {
> > +return r;
> > +}
> > +
> > +r = vhost_vdpa_cvq_map_buf(>vhost_vdpa, s->cvq_cmd_in_buffer,
> > +   vhost_vdpa_net_cvq_cmd_page_len(), true);
> > +if (unlikely(r < 0)) {
> >  vhost_vdpa_cvq_unmap_buf(>vhost_vdpa, s->cvq_cmd_out_buffer);
> > -return false;
> >  }
> >
> > -iov[1].iov_len = 

Re: [PATCH v7 08/12] vdpa: Move command buffers map to start of net device

2022-08-09 Thread Jason Wang
On Fri, Aug 5, 2022 at 2:29 AM Eugenio Pérez  wrote:
>
> As this series will reuse them to restore the device state at the end of
> a migration (or a device start), let's allocate only once at the device
> start so we don't duplicate their map and unmap.
>
> Signed-off-by: Eugenio Pérez 
> ---
>  net/vhost-vdpa.c | 123 ++-
>  1 file changed, 58 insertions(+), 65 deletions(-)
>
> diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> index 55e8a39a56..2c6a26cca0 100644
> --- a/net/vhost-vdpa.c
> +++ b/net/vhost-vdpa.c
> @@ -263,29 +263,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void)
>  return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), 
> qemu_real_host_page_size());
>  }
>
> -/** Copy and map a guest buffer. */
> -static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
> -   const struct iovec *out_data,
> -   size_t out_num, size_t data_len, void 
> *buf,
> -   size_t *written, bool write)
> +/** Map CVQ buffer. */
> +static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t 
> size,
> +  bool write)
>  {
>  DMAMap map = {};
>  int r;
>
> -if (unlikely(!data_len)) {
> -qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n",
> -  __func__, write ? "in" : "out");
> -return false;
> -}
> -
> -*written = iov_to_buf(out_data, out_num, 0, buf, data_len);
>  map.translated_addr = (hwaddr)(uintptr_t)buf;
> -map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
> +map.size = size - 1;

Just noticed this, I think I've asked for the reason before but I
don't remember the answer.

But it looks like a hint of a defect of the current API design.

Thanks

>  map.perm = write ? IOMMU_RW : IOMMU_RO,
>  r = vhost_iova_tree_map_alloc(v->iova_tree, );
>  if (unlikely(r != IOVA_OK)) {
>  error_report("Cannot map injected element");
> -return false;
> +return r;
>  }
>
>  r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), 
> buf,
> @@ -294,50 +285,58 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
>  goto dma_map_err;
>  }
>
> -return true;
> +return 0;
>
>  dma_map_err:
>  vhost_iova_tree_remove(v->iova_tree, );
> -return false;
> +return r;
>  }
>
> -/**
> - * Copy the guest element into a dedicated buffer suitable to be sent to NIC
> - *
> - * @iov: [0] is the out buffer, [1] is the in one
> - */
> -static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
> -VirtQueueElement *elem,
> -struct iovec *iov)
> +static int vhost_vdpa_net_cvq_prepare(NetClientState *nc)
>  {
> -size_t in_copied;
> -bool ok;
> +VhostVDPAState *s;
> +int r;
>
> -iov[0].iov_base = s->cvq_cmd_out_buffer;
> -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, elem->out_sg, elem->out_num,
> -vhost_vdpa_net_cvq_cmd_len(), 
> iov[0].iov_base,
> -[0].iov_len, false);
> -if (unlikely(!ok)) {
> -return false;
> +assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
> +
> +s = DO_UPCAST(VhostVDPAState, nc, nc);
> +if (!s->vhost_vdpa.shadow_vqs_enabled) {
> +return 0;
>  }
>
> -iov[1].iov_base = s->cvq_cmd_in_buffer;
> -ok = vhost_vdpa_cvq_map_buf(>vhost_vdpa, NULL, 0,
> -sizeof(virtio_net_ctrl_ack), iov[1].iov_base,
> -_copied, true);
> -if (unlikely(!ok)) {
> +r = vhost_vdpa_cvq_map_buf(>vhost_vdpa, s->cvq_cmd_out_buffer,
> +   vhost_vdpa_net_cvq_cmd_page_len(), false);
> +if (unlikely(r < 0)) {
> +return r;
> +}
> +
> +r = vhost_vdpa_cvq_map_buf(>vhost_vdpa, s->cvq_cmd_in_buffer,
> +   vhost_vdpa_net_cvq_cmd_page_len(), true);
> +if (unlikely(r < 0)) {
>  vhost_vdpa_cvq_unmap_buf(>vhost_vdpa, s->cvq_cmd_out_buffer);
> -return false;
>  }
>
> -iov[1].iov_len = sizeof(virtio_net_ctrl_ack);
> -return true;
> +return r;
> +}
> +
> +static void vhost_vdpa_net_cvq_stop(NetClientState *nc)
> +{
> +VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
> +
> +assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
> +
> +if (s->vhost_vdpa.shadow_vqs_enabled) {
> +vhost_vdpa_cvq_unmap_buf(>vhost_vdpa, s->cvq_cmd_out_buffer);
> +vhost_vdpa_cvq_unmap_buf(>vhost_vdpa, s->cvq_cmd_in_buffer);
> +}
>  }
>
>  static NetClientInfo net_vhost_vdpa_cvq_info = {
>  .type = NET_CLIENT_DRIVER_VHOST_VDPA,
>  .size = sizeof(VhostVDPAState),
>  .receive = vhost_vdpa_receive,
> +.prepare = vhost_vdpa_net_cvq_prepare,
> +.stop = vhost_vdpa_net_cvq_stop,
>  .cleanup =