Am Mo., 29. Juni 2026 um 10:28 Uhr schrieb Manos Pitsidianakis
<[email protected]>:
>
> On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <[email protected]>
> wrote:
> >From: Volker Rümelin <[email protected]>
> >
> >The virtio-sound device is currently not migratable. Add the
> >missing VMSTATE fields, enable migration and reconnect the audio
> >streams after migration.
> >
> >The queue_inuse[] array variables mimic the inuse variable in
> >struct VirtQueue which is private. They are needed to restart
> >the virtio queues after migration.
> >
> >Signed-off-by: Volker Rümelin <[email protected]>
> >[AM: trivial rebase changes]
> >Signed-off-by: Alexander Mikhalitsyn <[email protected]>
> >---
> >v3:
> > - added latency_bytes field to VMStateDescription
> >
> > As suggested by Marc-André Lureau:
> > - removed the "rc" variable from virtio_snd_post_load()
> > - dropped info field from VMStateDescription, because
> > it can't be modified by guest and initialized only from realize
> > - added minimum_version_id/version_id so we can extend
> > VMStateDescription
> > without breaking compatibility in the future
> >---
> > hw/audio/virtio-snd.c | 80 +++++++++++++++++++++++++++++++----
> > include/hw/audio/virtio-snd.h | 1 +
> > 2 files changed, 73 insertions(+), 8 deletions(-)
> >
> >diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> >index 81ba1e1a277..7af0b63c03b 100644
> >--- a/hw/audio/virtio-snd.c
> >+++ b/hw/audio/virtio-snd.c
> >@@ -24,7 +24,6 @@
> > #include "qapi/error.h"
> > #include "hw/audio/virtio-snd.h"
> >
> >-#define VIRTIO_SOUND_VM_VERSION 1
> > #define VIRTIO_SOUND_JACK_DEFAULT 0
> > #define VIRTIO_SOUND_STREAM_DEFAULT 2
> > #define VIRTIO_SOUND_CHMAP_DEFAULT 0
> >@@ -78,17 +77,40 @@ static uint32_t supported_rates =
> >BIT(VIRTIO_SND_PCM_RATE_5512)
> > | BIT(VIRTIO_SND_PCM_RATE_192000)
> > | BIT(VIRTIO_SND_PCM_RATE_384000);
> >
> >+static const VMStateDescription vmstate_virtio_snd_stream = {
> >+ .name = "virtio-sound-stream",
> >+ .version_id = 1,
> >+ .minimum_version_id = 1,
> >+ .fields = (const VMStateField[]) {
> >+ VMSTATE_UINT32(state, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT32(params.buffer_bytes, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT32(params.period_bytes, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT32(params.features, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT8(params.channels, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT8(params.format, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT8(params.rate, VirtIOSoundPCMStream),
> >+ VMSTATE_UINT32(latency_bytes, VirtIOSoundPCMStream),
> >+ VMSTATE_END_OF_LIST()
> >+ },
> >+};
> >+
> > static const VMStateDescription vmstate_virtio_snd_device = {
> >- .name = TYPE_VIRTIO_SND,
> >- .version_id = VIRTIO_SOUND_VM_VERSION,
> >- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
> >+ .name = "virtio-sound-device",
> >+ .version_id = 1,
> >+ .minimum_version_id = 1,
> >+ .fields = (const VMStateField[]) {
> >+ VMSTATE_UINT32_ARRAY(queue_inuse, VirtIOSound, VIRTIO_SND_VQ_MAX),
> >+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(streams, VirtIOSound,
> >+ snd_conf.streams,
> >+ vmstate_virtio_snd_stream, VirtIOSoundPCMStream),
> >+ VMSTATE_END_OF_LIST()
> >+ },
> > };
> >
> > static const VMStateDescription vmstate_virtio_snd = {
> >- .name = TYPE_VIRTIO_SND,
> >- .unmigratable = 1,
> >- .minimum_version_id = VIRTIO_SOUND_VM_VERSION,
> >- .version_id = VIRTIO_SOUND_VM_VERSION,
> >+ .name = "virtio-sound",
Dear Manos,
>
> Why change the name? It differentiates between the device impl and
> virtio-sound-pci wrapper device.
I'm not sure that I understand this point. Before this patch both
vmstate_virtio_snd and vmstate_virtio_snd_device
had the same name TYPE_VIRTIO_SND, we are trying to give the
distinctive names here. Please, elaborate on this.
Kind regards,
Alex
>
> >+ .version_id = 1,
> >+ .minimum_version_id = 1,
> > .fields = (const VMStateField[]) {
> > VMSTATE_VIRTIO_DEVICE,
> > VMSTATE_END_OF_LIST()
> >@@ -799,6 +821,7 @@ process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd)
> > sizeof(virtio_snd_hdr));
> > virtqueue_push(cmd->vq, cmd->elem,
> > sizeof(virtio_snd_hdr) + cmd->payload_size);
> >+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] -= 1;
>
> Let's do a g_assert that this is > 0 before decrementing it.
Great idea, I will address this in v4.
>
> > virtio_notify(VIRTIO_DEVICE(s), cmd->vq);
> > }
> >
> >@@ -845,6 +868,7 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev,
> >VirtQueue *vq)
> >
> > elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
> > while (elem) {
> >+ s->queue_inuse[VIRTIO_SND_VQ_CONTROL] += 1;
> > cmd = g_new0(virtio_snd_ctrl_command, 1);
> > cmd->elem = elem;
> > cmd->vq = vq;
> >@@ -955,6 +979,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice
> >*vdev, VirtQueue *vq)
> > goto tx_err;
> > }
> >
> >+ vsnd->queue_inuse[VIRTIO_SND_VQ_TX] += 1;
> > size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
> >
> > buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
> >@@ -1034,6 +1059,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice
> >*vdev, VirtQueue *vq)
> > goto rx_err;
> > }
> >
> >+ vsnd->queue_inuse[VIRTIO_SND_VQ_RX] += 1;
> > size = iov_size(elem->in_sg, elem->in_num) -
> > sizeof(virtio_snd_pcm_status);
> > buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
> >@@ -1175,6 +1201,7 @@ static inline void
> >return_tx_buffer(VirtIOSoundPCMStream *stream,
> > virtqueue_push(buffer->vq,
> > buffer->elem,
> > sizeof(virtio_snd_pcm_status));
> >+ stream->s->queue_inuse[VIRTIO_SND_VQ_TX] -= 1;
>
> Ditto
+
>
> > virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
> > QSIMPLEQ_REMOVE(&stream->queue,
> > buffer,
> >@@ -1268,6 +1295,7 @@ static inline void
> >return_rx_buffer(VirtIOSoundPCMStream *stream,
> > virtqueue_push(buffer->vq,
> > buffer->elem,
> > sizeof(virtio_snd_pcm_status) + buffer->size);
> >+ stream->s->queue_inuse[VIRTIO_SND_VQ_RX] -= 1;
>
> Ditto
+
>
> > virtio_notify(VIRTIO_DEVICE(stream->s), buffer->vq);
> > QSIMPLEQ_REMOVE(&stream->queue,
> > buffer,
> >@@ -1386,6 +1414,37 @@ static void virtio_snd_unrealize(DeviceState *dev)
> > virtio_cleanup(vdev);
> > }
> >
> >+static int virtio_snd_post_load(VirtIODevice *vdev)
> >+{
> >+ VirtIOSound *s = VIRTIO_SND(vdev);
> >+ uint32_t i;
> >+
> >+ for (i = 0; i < s->snd_conf.streams; i++) {
> >+ struct VirtIOSoundPCMStream *stream;
> >+
> >+ stream = virtio_snd_pcm_get_stream(s, i);
> >+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> >+ virtio_snd_pcm_open(stream);
> >+
> >+ if (stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE) {
> >+ virtio_snd_pcm_set_active(stream, true);
> >+ }
> >+ }
> >+ }
> >+
> >+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
> >+ if (s->queue_inuse[i]) {
> >+ if (!virtqueue_rewind(s->queues[i], s->queue_inuse[i])) {
> >+ error_report(
> >+ "virtio-snd: could not rewind %u elements in queue %u",
> >+ s->queue_inuse[i], i);
> >+ }
> >+ s->queue_inuse[i] = 0;
> >+ }
> >+ }
> >+
> >+ return 0;
> >+}
> >
> > static void virtio_snd_reset(VirtIODevice *vdev)
> > {
> >@@ -1418,6 +1477,10 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> > virtio_snd_pcm_buffer_free(buffer);
> > }
> > }
> >+
> >+ for (i = 0; i < VIRTIO_SND_VQ_MAX; i++) {
> >+ vsnd->queue_inuse[i] = 0;
> >+ }
> > }
> >
> > static void virtio_snd_class_init(ObjectClass *klass, const void *data)
> >@@ -1431,6 +1494,7 @@ static void virtio_snd_class_init(ObjectClass *klass,
> >const void *data)
> >
> > dc->vmsd = &vmstate_virtio_snd;
> > vdc->vmsd = &vmstate_virtio_snd_device;
> >+ vdc->post_load = virtio_snd_post_load;
> > vdc->realize = virtio_snd_realize;
> > vdc->unrealize = virtio_snd_unrealize;
> > vdc->get_config = virtio_snd_get_config;
> >diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
> >index 85d5d7c8619..384d2868c19 100644
> >--- a/include/hw/audio/virtio-snd.h
> >+++ b/include/hw/audio/virtio-snd.h
> >@@ -194,6 +194,7 @@ struct VirtIOSound {
> > VirtIODevice parent_obj;
> >
> > VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> >+ uint32_t queue_inuse[VIRTIO_SND_VQ_MAX];
> > uint64_t features;
> > VirtIOSoundPCMStream *streams;
> > AudioBackend *audio_be;
> >--
> >2.47.3
> >