Skip to content

Commit

Permalink
virtio-sound: add realize() error cleanup path
Browse files Browse the repository at this point in the history
QEMU crashes on exit when a virtio-sound device has failed to
realise. Its vmstate field was not cleaned up properly with
qemu_del_vm_change_state_handler().

This patch changes the realize() order as

1. Validate the given configuration values (no resources allocated
   by us either on success or failure)
2. Try AUD_register_card() and return on failure (no resources allocated
   by us on failure)
3. Initialize vmstate, virtio device, heap allocations and stream
   parameters at once.
   If error occurs, goto error_cleanup label which calls
   virtio_snd_unrealize(). This cleans up all resources made in steps
   1-3.

Reported-by: Volker Rümelin <vr_qemu@t-online.de>
Fixes: 2880e67 ("Add virtio-sound device stub")
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-Id: <20231116072046.4002957-1-manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
  • Loading branch information
epilys authored and mstsirkin committed Dec 2, 2023
1 parent 691d3d8 commit f785618
Showing 1 changed file with 22 additions and 17 deletions.
39 changes: 22 additions & 17 deletions hw/audio/virtio-snd.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available);
static void virtio_snd_process_cmdq(VirtIOSound *s);
static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
static void virtio_snd_pcm_in_cb(void *data, int available);
static void virtio_snd_unrealize(DeviceState *dev);

static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
| BIT(VIRTIO_SND_PCM_FMT_U8)
Expand Down Expand Up @@ -1065,23 +1066,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
virtio_snd_pcm_set_params default_params = { 0 };
uint32_t status;

vsnd->pcm = NULL;
vsnd->vmstate =
qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);

trace_virtio_snd_realize(vsnd);

vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
vsnd->pcm->snd = vsnd;
vsnd->pcm->streams =
g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
vsnd->pcm->pcm_params =
g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);

virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);

/* set number of jacks and streams */
/* check number of jacks and streams */
if (vsnd->snd_conf.jacks > 8) {
error_setg(errp,
"Invalid number of jacks: %"PRIu32,
Expand All @@ -1106,6 +1093,19 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
return;
}

vsnd->vmstate =
qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd);

vsnd->pcm = g_new0(VirtIOSoundPCM, 1);
vsnd->pcm->snd = vsnd;
vsnd->pcm->streams =
g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
vsnd->pcm->pcm_params =
g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);

virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);

/* set default params for all streams */
default_params.features = 0;
default_params.buffer_bytes = cpu_to_le32(8192);
Expand All @@ -1130,16 +1130,21 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp)
error_setg(errp,
"Can't initialize stream params, device responded with %s.",
print_code(status));
return;
goto error_cleanup;
}
status = virtio_snd_pcm_prepare(vsnd, i);
if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
error_setg(errp,
"Can't prepare streams, device responded with %s.",
print_code(status));
return;
goto error_cleanup;
}
}

return;

error_cleanup:
virtio_snd_unrealize(dev);
}

static inline void return_tx_buffer(VirtIOSoundPCMStream *stream,
Expand Down

0 comments on commit f785618

Please sign in to comment.