On 9/24/25 22:47, [email protected] wrote:
> From: Dongwon Kim <[email protected]>
> 
> When the host KVM/QEMU resumes from hibernation, it loses all graphics
> resources previously submitted by the guest OS, as the QEMU process is
> terminated during the suspend-resume cycle. This leads to invalid resource
> errors when the guest OS attempts to interact with the host using those
> resources after resumption.
> 
> To resolve this, the virtio-gpu driver now tracks all active 
> virtio_gpu_objects
> and provides a mechanism to restore them by re-submitting the objects to QEMU
> when needed (e.g., during resume from hibernation).
> 
> v2: - Attach backing is done if bo->attached was set before
> 
> v3: - Restoration of virtio-gpu resources is no longer triggered via .restore;
>       instead, it is handled by a PM notifier only during hibernation.
> 
> Cc: Dmitry Osipenko <[email protected]>
> Cc: Vivek Kasireddy <[email protected]>
> Signed-off-by: Dongwon Kim <[email protected]>
> ---
>  drivers/gpu/drm/virtio/virtgpu_drv.h    | 10 ++++
>  drivers/gpu/drm/virtio/virtgpu_kms.c    |  1 +
>  drivers/gpu/drm/virtio/virtgpu_object.c | 71 +++++++++++++++++++++++++
>  3 files changed, 82 insertions(+)
> 
> diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h 
> b/drivers/gpu/drm/virtio/virtgpu_drv.h
> index 1279f998c8e0..55f836378237 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_drv.h
> +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
> @@ -126,6 +126,12 @@ struct virtio_gpu_object_array {
>       struct drm_gem_object *objs[] __counted_by(total);
>  };
>  
> +struct virtio_gpu_object_restore {
> +     struct virtio_gpu_object *bo;
> +     struct virtio_gpu_object_params params;
> +     struct list_head node;
> +};
> +
>  struct virtio_gpu_vbuffer;
>  struct virtio_gpu_device;
>  
> @@ -265,6 +271,7 @@ struct virtio_gpu_device {
>       struct work_struct obj_free_work;
>       spinlock_t obj_free_lock;
>       struct list_head obj_free_list;
> +     struct list_head obj_restore;
>  
>       struct virtio_gpu_drv_capset *capsets;
>       uint32_t num_capsets;
> @@ -479,6 +486,9 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo);
>  
>  int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
>                              uint32_t *resid);
> +
> +int virtio_gpu_object_restore_all(struct virtio_gpu_device *vgdev);
> +
>  /* virtgpu_prime.c */
>  int virtio_gpu_resource_assign_uuid(struct virtio_gpu_device *vgdev,
>                                   struct virtio_gpu_object *bo);
> diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c 
> b/drivers/gpu/drm/virtio/virtgpu_kms.c
> index cbebe19c3fb3..08f8e71a7072 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_kms.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
> @@ -162,6 +162,7 @@ int virtio_gpu_init(struct virtio_device *vdev, struct 
> drm_device *dev)
>       vgdev->fence_drv.context = dma_fence_context_alloc(1);
>       spin_lock_init(&vgdev->fence_drv.lock);
>       INIT_LIST_HEAD(&vgdev->fence_drv.fences);
> +     INIT_LIST_HEAD(&vgdev->obj_restore);
>       INIT_LIST_HEAD(&vgdev->cap_cache);
>       INIT_WORK(&vgdev->config_changed_work,
>                 virtio_gpu_config_changed_work_func);
> diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c 
> b/drivers/gpu/drm/virtio/virtgpu_object.c
> index e6363c887500..28fdfc70fa49 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_object.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_object.c
> @@ -61,6 +61,38 @@ static void virtio_gpu_resource_id_put(struct 
> virtio_gpu_device *vgdev, uint32_t
>               ida_free(&vgdev->resource_ida, id - 1);
>  }
>  
> +static void virtio_gpu_object_add_restore_list(struct virtio_gpu_device 
> *vgdev,
> +                                            struct virtio_gpu_object *bo,
> +                                            struct virtio_gpu_object_params 
> *params)
> +{
> +     struct virtio_gpu_object_restore *new;
> +
> +     new = kvmalloc(sizeof(*new), GFP_KERNEL);
> +     if (!new) {
> +             DRM_ERROR("Fail to allocate virtio_gpu_object_restore");
> +             return;
> +     }
> +
> +     new->bo = bo;
> +     memcpy(&new->params, params, sizeof(*params));
> +
> +     list_add_tail(&new->node, &vgdev->obj_restore);
> +}
> +
> +static void virtio_gpu_object_del_restore_list(struct virtio_gpu_device 
> *vgdev,
> +                                            struct virtio_gpu_object *bo)
> +{
> +     struct virtio_gpu_object_restore *curr, *tmp;
> +
> +     list_for_each_entry_safe(curr, tmp, &vgdev->obj_restore, node) {
> +             if (bo == curr->bo) {
> +                     list_del(&curr->node);
> +                     kvfree(curr);
> +                     break;
> +             }
> +     }
> +}
> +
>  void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo)
>  {
>       struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
> @@ -84,6 +116,7 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object 
> *bo)
>               drm_gem_object_release(&bo->base.base);
>               kfree(bo);
>       }
> +     virtio_gpu_object_del_restore_list(vgdev, bo);
>  }
>  
>  static void virtio_gpu_free_object(struct drm_gem_object *obj)
> @@ -258,6 +291,8 @@ int virtio_gpu_object_create(struct virtio_gpu_device 
> *vgdev,
>               virtio_gpu_object_attach(vgdev, bo, ents, nents);
>       }
>  
> +     /* add submitted object to restore list */
> +     virtio_gpu_object_add_restore_list(vgdev, bo, params);
>       *bo_ptr = bo;
>       return 0;
>  
> @@ -271,3 +306,39 @@ int virtio_gpu_object_create(struct virtio_gpu_device 
> *vgdev,
>       drm_gem_shmem_free(shmem_obj);
>       return ret;
>  }
> +
> +int virtio_gpu_object_restore_all(struct virtio_gpu_device *vgdev)
> +{
> +     struct virtio_gpu_object_restore *curr, *tmp;
> +     struct virtio_gpu_mem_entry *ents;
> +     unsigned int nents;
> +     int ret;
> +
> +     list_for_each_entry_safe(curr, tmp, &vgdev->obj_restore, node) {
> +             ret = virtio_gpu_object_shmem_init(vgdev, curr->bo, &ents, 
> &nents);
> +             if (ret)
> +                     break;
> +
> +             if (curr->params.blob) {
> +                     virtio_gpu_cmd_resource_create_blob(vgdev, curr->bo, 
> &curr->params,
> +                                                         ents, nents);
> +             } else if (curr->params.virgl) {
> +                     virtio_gpu_cmd_resource_create_3d(vgdev, curr->bo, 
> &curr->params,
> +                                                       NULL, NULL);
> +
> +                     if (curr->bo->attached) {
> +                             curr->bo->attached = false;
> +                             virtio_gpu_object_attach(vgdev, curr->bo, ents, 
> nents);
> +                     }
> +             } else {
> +                     virtio_gpu_cmd_create_resource(vgdev, curr->bo, 
> &curr->params,
> +                                                    NULL, NULL);
> +                     if (curr->bo->attached) {
> +                             curr->bo->attached = false;
> +                             virtio_gpu_object_attach(vgdev, curr->bo, ents, 
> nents);
> +                     }
> +             }
> +     }
> +
> +     return ret;
> +}

Tested-by: Dmitry Osipenko <[email protected]>

-- 
Best regards,
Dmitry

Reply via email to