From dc2deaba4852e3324a4558a8bd29c58ce3299699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 31 May 2021 12:19:28 +0200 Subject: hw/display/virtio-gpu: Fix memory leak (CID 1453811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid leaking memory on the error path, reorder the code as: - check the parameters first - check resource already existing - finally allocate memory Reported-by: Coverity (CID 1453811: RESOURCE_LEAK) Fixes: e0933d91b1c ("virtio-gpu: Add virtio_gpu_resource_create_blob") Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210531101928.1662732-1-philmd@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6b7f643..990e71f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -340,37 +340,31 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, return; } - res = virtio_gpu_find_resource(g, cblob.resource_id); - if (res) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", - __func__, cblob.resource_id); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; - return; - } - - res = g_new0(struct virtio_gpu_simple_resource, 1); - res->resource_id = cblob.resource_id; - res->blob_size = cblob.size; - if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_GUEST && cblob.blob_flags != VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid memory type\n", __func__); cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - g_free(res); return; } - if (res->iov) { - cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + if (virtio_gpu_find_resource(g, cblob.resource_id)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, cblob.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; return; } + res = g_new0(struct virtio_gpu_simple_resource, 1); + res->resource_id = cblob.resource_id; + res->blob_size = cblob.size; + ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob), cmd, &res->addrs, &res->iov, &res->iov_cnt); - if (ret != 0) { + if (ret != 0 || res->iov) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + g_free(res); return; } -- cgit v1.1 From 39b8a183e2f399d19f3ab6a3db44c7c74774dabd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Jul 2021 11:33:46 +0200 Subject: qxl: remove assert in qxl_pre_save. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 551dbd0846d2 ("migration: check pre_save return in vmstate_save_state") the pre_save hook can fail. So lets finally use that to drop the guest-triggerable assert in qxl_pre_save(). Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-Id: <20210721093347.338536-2-kraxel@redhat.com> --- hw/display/qxl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 84f9908..3867b94 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2283,7 +2283,9 @@ static int qxl_pre_save(void *opaque) } else { d->last_release_offset = (uint8_t *)d->last_release - ram_start; } - assert(d->last_release_offset < d->vga.vram_size); + if (d->last_release_offset < d->vga.vram_size) { + return 1; + } return 0; } -- cgit v1.1 From dcc5fc2a3adb9ec4b196f82ebe4079bc88f3c91e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Jul 2021 11:33:47 +0200 Subject: Revert "qxl: add migration blocker to avoid pre-save assert" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 86dbcdd9c7590d06db89ca256c5eaf0b4aba8858. The pre-save assert is gone now, so the migration blocker is not needed any more. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-Id: <20210721093347.338536-3-kraxel@redhat.com> --- hw/display/qxl.c | 31 ------------------------------- hw/display/qxl.h | 1 - 2 files changed, 32 deletions(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 3867b94..43482d4 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -30,7 +30,6 @@ #include "qemu/module.h" #include "hw/qdev-properties.h" #include "sysemu/runstate.h" -#include "migration/blocker.h" #include "migration/vmstate.h" #include "trace.h" @@ -666,30 +665,6 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "cmd", ext); - { - /* - * Windows 8 drivers place qxl commands in the vram - * (instead of the ram) bar. We can't live migrate such a - * guest, so add a migration blocker in case we detect - * this, to avoid triggering the assert in pre_save(). - * - * https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa - */ - void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); - if (msg != NULL && ( - msg < (void *)qxl->vga.vram_ptr || - msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) { - if (!qxl->migration_blocker) { - Error *local_err = NULL; - error_setg(&qxl->migration_blocker, - "qxl: guest bug: command not in ram bar"); - migrate_add_blocker(qxl->migration_blocker, &local_err); - if (local_err) { - error_report_err(local_err); - } - } - } - } trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); return true; default: @@ -1283,12 +1258,6 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) qemu_spice_create_host_memslot(&d->ssd); qxl_soft_reset(d); - if (d->migration_blocker) { - migrate_del_blocker(d->migration_blocker); - error_free(d->migration_blocker); - d->migration_blocker = NULL; - } - if (startstop) { qemu_spice_display_start(); } diff --git a/hw/display/qxl.h b/hw/display/qxl.h index 379d330..30d21f4 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -39,7 +39,6 @@ struct PCIQXLDevice { uint32_t cmdlog; uint32_t guest_bug; - Error *migration_blocker; enum qxl_mode mode; uint32_t cmdflags; -- cgit v1.1 From 02f9725f3df8a0e8f0a209d7436fad04e1ac190e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 5 Jul 2021 14:42:18 +0400 Subject: hw/display: fail early when multiple virgl devices are requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids failing to initialize virgl and crashing later on, and clear the user expectations. Signed-off-by: Marc-André Lureau Reviewed-by: Mark Cave-Ayland Message-Id: <20210705104218.1161101-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu-gl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 7ab93bf..b1035e1 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -113,6 +113,11 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) return; #endif + if (!object_resolve_path_type("", TYPE_VIRTIO_GPU_GL, NULL)) { + error_setg(errp, "at most one %s device is permitted", TYPE_VIRTIO_GPU_GL); + return; + } + if (!display_opengl) { error_setg(errp, "opengl is not available"); return; -- cgit v1.1 From f29d52611c73347a2fc0fcea62e6197383b18fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 1 Jul 2021 10:24:21 +0400 Subject: vl: add virtio-vga-gl to the default_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not instantiate an extra default VGA device if -device virtio-vga-gl is provided. Related to commit b36eb8860f8f4a9c6f131c3fd380116a3017e022 ("virtio-gpu: add virtio-vga-gl") Signed-off-by: Marc-André Lureau Message-Id: <20210701062421.721414-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- softmmu/vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/softmmu/vl.c b/softmmu/vl.c index 4df1496..a6c17fa 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -202,6 +202,7 @@ static struct { { .driver = "virtio-vga", .flag = &default_vga }, { .driver = "ati-vga", .flag = &default_vga }, { .driver = "vhost-user-vga", .flag = &default_vga }, + { .driver = "virtio-vga-gl", .flag = &default_vga }, }; static QemuOptsList qemu_rtc_opts = { -- cgit v1.1 From 8a13b9bc0f283caff4333c75bc396a963f47ce5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 2 Jul 2021 16:32:21 +0400 Subject: hw/display: fix virgl reset regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit 49afbca3b00e8e517d54964229a794b51768deaf ("virtio-gpu: drop use_virgl_renderer"), use_virgl_renderer was preventing calling GL functions from non-GL context threads. The innocuously looking g->parent_obj.use_virgl_renderer = false; was set the first time virtio_gpu_gl_reset() was called, during pc_machine_reset() in the main thread. Further virtio_gpu_gl_reset() calls in IO threads, without associated GL context, were thus skipping GL calls and avoided warnings or crashes (see also https://gitlab.freedesktop.org/virgl/virglrenderer/-/issues/226). Signed-off-by: Marc-André Lureau Message-Id: <20210702123221.942432-1-marcandre.lureau@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu-gl.c | 22 +++++++++++----------- hw/display/virtio-gpu-virgl.c | 8 ++++++-- include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index b1035e1..6cc4313 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -51,12 +51,7 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) { VirtIOGPU *g = VIRTIO_GPU(b); - VirtIOGPUGL *gl = VIRTIO_GPU_GL(b); - if (gl->renderer_reset) { - gl->renderer_reset = false; - virtio_gpu_virgl_reset(g); - } virtio_gpu_process_cmdq(g); } @@ -74,6 +69,10 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtio_gpu_virgl_init(g); gl->renderer_inited = true; } + if (gl->renderer_reset) { + gl->renderer_reset = false; + virtio_gpu_virgl_reset(g); + } cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); while (cmd) { @@ -95,12 +94,13 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) virtio_gpu_reset(vdev); - if (gl->renderer_inited) { - if (g->parent_obj.renderer_blocked) { - gl->renderer_reset = true; - } else { - virtio_gpu_virgl_reset(g); - } + /* + * GL functions must be called with the associated GL context in main + * thread, and when the renderer is unblocked. + */ + if (gl->renderer_inited && !gl->renderer_reset) { + virtio_gpu_virgl_reset_scanout(g); + gl->renderer_reset = true; } } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 092c6dc..18d0549 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -588,17 +588,21 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g) virtio_gpu_fence_poll(g); } -void virtio_gpu_virgl_reset(VirtIOGPU *g) +void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g) { int i; - virgl_renderer_reset(); for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL); dpy_gl_scanout_disable(g->parent_obj.scanout[i].con); } } +void virtio_gpu_virgl_reset(VirtIOGPU *g) +{ + virgl_renderer_reset(); +} + int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index bcf54d9..24c6628 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -279,6 +279,7 @@ int virtio_gpu_update_dmabuf(VirtIOGPU *g, void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); +void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); -- cgit v1.1