diff options
author | Manos Pitsidianakis <manos.pitsidianakis@linaro.org> | 2023-11-16 09:20:46 +0200 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2023-12-02 15:56:49 -0500 |
commit | f7856181849939ecb096dd1d0068b674fe2c69ff (patch) | |
tree | 6aac24cea989fcef25288aafd4764724989b236c /hw/audio | |
parent | 691d3d8bbde16abd002a2590fa422b079d0c8468 (diff) | |
download | qemu-f7856181849939ecb096dd1d0068b674fe2c69ff.zip qemu-f7856181849939ecb096dd1d0068b674fe2c69ff.tar.gz qemu-f7856181849939ecb096dd1d0068b674fe2c69ff.tar.bz2 |
virtio-sound: add realize() error cleanup path
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: 2880e676c000 ("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>
Diffstat (limited to 'hw/audio')
-rw-r--r-- | hw/audio/virtio-snd.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c index 83e9785..3c9f94e 100644 --- a/hw/audio/virtio-snd.c +++ b/hw/audio/virtio-snd.c @@ -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) @@ -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, @@ -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); @@ -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, |