On Mon, Oct 14, 2024 at 11:16 PM Laurent Vivier <lviv...@redhat.com> wrote:
>
> On 14/10/2024 10:30, Laurent Vivier wrote:
> > Hi Akihiko,
> >
> > On 04/06/2024 09:37, Jason Wang wrote:
> >> From: Akihiko Odaki <akihiko.od...@daynix.com>
> >>
> >> Multiqueue usage is not negotiated yet when realizing. If more than
> >> one queue is added and the guest never requests to enable multiqueue,
> >> the extra queues will not be deleted when unrealizing and leak.
> >>
> >> Fixes: f9d6dbf0bf6e ("virtio-net: remove virtio queues if the guest 
> >> doesn't support
> >> multiqueue")
> >> Signed-off-by: Akihiko Odaki <akihiko.od...@daynix.com>
> >> Signed-off-by: Jason Wang <jasow...@redhat.com>
> >> ---
> >>   hw/net/virtio-net.c | 4 +---
> >>   1 file changed, 1 insertion(+), 3 deletions(-)
> >>
> >> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> >> index 3cee2ef3ac..a8db8bfd9c 100644
> >> --- a/hw/net/virtio-net.c
> >> +++ b/hw/net/virtio-net.c
> >> @@ -3743,9 +3743,7 @@ static void virtio_net_device_realize(DeviceState 
> >> *dev, Error **errp)
> >>       n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n),
> >>                                       n->net_conf.tx_queue_size);
> >> -    for (i = 0; i < n->max_queue_pairs; i++) {
> >> -        virtio_net_add_queue(n, i);
> >> -    }
> >> +    virtio_net_add_queue(n, 0);
> >>       n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
> >>       qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
> >
> > This change breaks virtio net migration when multiqueue is enabled.
> >
> > I think this is because virtqueues are half initialized after migration : 
> > they are
> > initialized on guest side (kernel is using them) but not on QEMU side 
> > (realized has only
> > initialized one). After migration, they are not initialized by the call to
> > virtio_net_set_multiqueue() from virtio_net_set_features() because 
> > virtio_get_num_queues()
> > reports already n->max_queue_pairs as this value is coming from the source 
> > guest memory.
> >
> > I don't think we have a way to half-initialize a virtqueue (to initialize 
> > them only on
> > QEMU side as they are already initialized on kernel side).
> >
> > I think this change should be reverted to fix the migration issue.
> >
>
> Moreover, if I look in the code of virtio_load() and virtio_add_queue() we 
> can guess it's
> not correct to migrate a virtqueue that is not initialized on the destination 
> side because
> fields like 'vdev->vq[i].handle_output' or 'vdev->vq[i].used_elems' cannot be 
> initialized
> by virtio_load() and neither by virtio_add_queue() after virtio_load() as 
> fields like
> 'vring.num' are already initialized by virtio_load().
>
> For instance, in virtio_load() we set:
>
>      for (i = 0; i < num; i++) {
>          vdev->vq[i].vring.num = qemu_get_be32(f);
>
> and in virtio_add_queue() we search for the firt available queue to add with:
>
>      for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
>          if (vdev->vq[i].vring.num == 0)
>              break;
>      }
>
> So virtio_add_queue() cannot be used to set:
>
>      vdev->vq[i].handle_output = handle_output;
>      vdev->vq[i].used_elems = g_new0(VirtQueueElement, queue_size);
>
> Moreover it would overwrite fields already set by virtio_load():
>
>      vdev->vq[i].vring.num = queue_size;
>      vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
>
> It also explains why virtio_net_change_num_queue_pairs() (indirectly called by
> virtio_net_set_features()) doesn't update the queue pair numbers: vring.num 
> is already set
> so it thinks there is no more queues to add.
>
> Thanks,
> LAurent
>

I agree.

Laurent, would you like to send a patch to revert this?

Thanks

>


Reply via email to