On Sat, Oct 19, 2024 at 8:38 PM Akihiko Odaki <akihiko.od...@daynix.com> wrote: > > On 2024/10/18 13:50, Jason Wang wrote: > > On Thu, Oct 17, 2024 at 5:42 PM Akihiko Odaki <akihiko.od...@daynix.com> > > wrote: > >> > >> On 2024/10/17 18:17, Laurent Vivier wrote: > >>> On 17/10/2024 11:07, Akihiko Odaki wrote: > >>>> On 2024/10/17 16:32, Laurent Vivier wrote: > >>>>> On 17/10/2024 08:59, Jason Wang wrote: > >>>>>> 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? > >>>>>> > >>>>> > >>>>> Yes. I will also try to fix the leak in unrealize that the patch > >>>>> wanted to fix initially. > >>>> > >>>> I wrote a fix so I will submit it once internal testing is done. You > >>>> can see the change at: > >>>> https://gitlab.com/akihiko.odaki/qemu-kvm/-/ > >>>> commit/22161221aa2d2031d7ad1be7701852083aa9109a > >>> > >>> It works fine for me but I don't know if it's a good idea to add queues > >>> while the state is loading. > >> > >> I couldn't come up with other options. The problem is that the number of > >> queues added during realization does not match with the loaded state. We > >> need to add queues after knowing the negotiated feature set and before > >> loading the queue states to fix this problem. > >> > >> Reverting will add queues that are used when the multiqueue feature is > >> negotiated so it will fix migration for such cases, but will also break > >> the other cases (i.e., the multiqueue feature is not negotiated) as it > >> adds too many queues. > >> > >> Regards, > >> Akihiko Odaki > > > > I wonder if the following is much more simpler: > > > > 1) introducing booleans whether the queue has been deleted > > 2) in unrelize, deleted only the queue that has not been deleted > > The memory leak problem is trivial to solve, but the problem with queue > state loading is not. We need to ensure the number of queues are > consistent with the number of loaded queues. > > We currently have too few queues if the multiqueue feature is > negotiated, which results in queues partially initialized with the > loaded state. Reverting will leave too many queues for the cases where > the multiqueue feature is not negotiated, which is also problematic > because virtio-net will reconfigure queues to reduce the number of > queues and dispose loaded states.
I'm not sure I would get here, if those queues were not visible to drivers. Why do we care? Thanks > > Regards, > Akihiko Odaki > > > > > ? > > > > Thanks > > > >> > >>> > >>> Jason, let me know which solution you prefer (revert or pre_load_queues > >>> helper). > >>> > >>> CC'ing MST > >>> > >>> Thanks, > >>> Laurent > >>> > >> > > >