[PATCH] hw/display/virtio-gpu: Block migration with large blobs

Akihiko Odaki posted 1 patch 1 week, 5 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260914-block-v1-1-4df9617573ca@rsg.ci.i.u-tokyo.ac.jp
Maintainers: "Alex Bennée" <alex.bennee@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Dmitry Osipenko <dmitry.osipenko@collabora.com>, "Michael S. Tsirkin" <mst@redhat.com>
hw/display/virtio-gpu.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
[PATCH] hw/display/virtio-gpu: Block migration with large blobs
Posted by Akihiko Odaki 1 week, 5 days ago
The blob size is encoded as a 64-bit integer in the virtio protocol, but
it is encoded as a 32-bit integer in the migration stream, and
a large blob whose size cannot be expressed in a 32-bit integer will
be corrupted after migration.

Block migration with such large blobs, and, if it is not possible, deny
creating a large blob.

Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection")
Fixes: 10b9ddbc83b9 ("Revert "virtio-gpu: block migration of VMs with blob=true"")
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
Supersedes: <20260727-blob-v2-1-d0b9af38a975@rsg.ci.i.u-tokyo.ac.jp>
("[PATCH v2] hw/display/virtio-gpu: Reject non-migratable large blobs")
---
 hw/display/virtio-gpu.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index bb0f41bb1e05..5d43ffb99184 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -27,6 +27,7 @@
 #include "hw/virtio/virtio-gpu-pixman.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/core/qdev-properties.h"
+#include "migration/blocker.h"
 #include "qemu/log.h"
 #include "qemu/memfd.h"
 #include "qemu/module.h"
@@ -35,6 +36,9 @@
 
 #define VIRTIO_GPU_VM_VERSION 1
 
+static size_t num_large_blobs;
+static Error *large_blob_blocker;
+
 static struct virtio_gpu_simple_resource *
 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
                                const char *caller, uint32_t *error);
@@ -355,6 +359,7 @@ end:
 static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
                                             struct virtio_gpu_ctrl_command *cmd)
 {
+    Error *local_err = NULL;
     struct virtio_gpu_simple_resource *res;
     struct virtio_gpu_resource_create_blob cblob;
     int ret;
@@ -415,6 +420,26 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
         }
     }
 
+    if (cblob.size > UINT32_MAX) {
+        if (!num_large_blobs) {
+            error_setg(&large_blob_blocker,
+                       "a large virtio-gpu blob is present");
+            if (migrate_add_blocker(&large_blob_blocker, &local_err)) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "%s: blocking migration for a large blob failed: %s\n",
+                              __func__, error_get_pretty(local_err));
+                error_free(local_err);
+                cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+                virtio_gpu_fini_udmabuf(res);
+                virtio_gpu_cleanup_mapping(g, res);
+                g_free(res);
+                return;
+            }
+        }
+
+        num_large_blobs++;
+    }
+
     QTAILQ_INSERT_HEAD(&g->reslist, res, next);
 }
 
@@ -460,6 +485,13 @@ static void virtio_gpu_resource_destroy(VirtIOGPU *g,
 {
     virtio_gpu_disable_scanout_for_resource(g, res->resource_id);
 
+    if (res->blob_size > UINT32_MAX) {
+        num_large_blobs--;
+        if (!num_large_blobs) {
+            migrate_del_blocker(&large_blob_blocker);
+        }
+    }
+
     qemu_pixman_image_unref(res->image);
     virtio_gpu_cleanup_mapping(g, res);
     QTAILQ_REMOVE(&g->reslist, res, next);

---
base-commit: 209b2afaface001c7d4d981e38f186afe7b24a50
change-id: 20260729-block-2efd66ec23cd

Best regards,
--  
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>