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: 2880e676c0
("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>
This commit is contained in:
parent
691d3d8bbd
commit
f785618184
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user