On 2025-07-17 10:35, David Francis wrote:
> CRIU restore of drm buffer objects requires the ability to create
> or import a buffer object with a specific gem handle.
>
> Add new drm ioctl DRM_IOCTL_GEM_CHANGE_HANDLE, which takes
> the gem handle of an object and moves that object to a
> specified new gem handle.
>
> This ioctl needs to call drm_prime_remove_buf_handle,
> but that function acquires the prime lock, which the ioctl
> needs to hold for other purposes.
>
> Make drm_prime_remove_buf_handle not acquire the prime lock,
> and change its other caller to reflect this.
>
> The rest of the kernel patches required to enable CRIU can be
> found at
> https://lore.kernel.org/dri-devel/20250617194536.538681-1-david.fran...@amd.com/
>
> v2 - Move documentation to UAPI headers
> v3 - Always return 0 on success
>
> Signed-off-by: David Francis <david.fran...@amd.com>

Acked-by: Felix Kuehling <felix.kuehl...@amd.com>


> ---
>  drivers/gpu/drm/drm_gem.c      | 56 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_internal.h |  4 +++
>  drivers/gpu/drm/drm_ioctl.c    |  1 +
>  drivers/gpu/drm/drm_prime.c    |  6 +---
>  include/uapi/drm/drm.h         | 23 ++++++++++++++
>  5 files changed, 85 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index c6240bab3fa5..b1d7b0655cbb 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -282,7 +282,12 @@ drm_gem_object_release_handle(int id, void *ptr, void 
> *data)
>       if (obj->funcs->close)
>               obj->funcs->close(obj, file_priv);
>  
> +     mutex_lock(&file_priv->prime.lock);
> +
>       drm_prime_remove_buf_handle(&file_priv->prime, id);
> +
> +     mutex_unlock(&file_priv->prime.lock);
> +
>       drm_vma_node_revoke(&obj->vma_node, file_priv);
>  
>       drm_gem_object_handle_put_unlocked(obj);
> @@ -933,6 +938,57 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
>       return ret;
>  }
>  
> +int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
> +                             struct drm_file *file_priv)
> +{
> +     struct drm_gem_change_handle *args = data;
> +     struct drm_gem_object *obj;
> +     int ret;
> +
> +     if (!drm_core_check_feature(dev, DRIVER_GEM))
> +             return -EOPNOTSUPP;
> +
> +     obj = drm_gem_object_lookup(file_priv, args->handle);
> +     if (!obj)
> +             return -ENOENT;
> +
> +     if (args->handle == args->new_handle)
> +             return 0;
> +
> +     mutex_lock(&file_priv->prime.lock);
> +
> +     spin_lock(&file_priv->table_lock);
> +     ret = idr_alloc(&file_priv->object_idr, obj,
> +             args->new_handle, args->new_handle + 1, GFP_NOWAIT);
> +     spin_unlock(&file_priv->table_lock);
> +
> +     if (ret < 0)
> +             goto out_unlock;
> +
> +     if (obj->dma_buf) {
> +             ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, 
> args->new_handle);
> +             if (ret < 0) {
> +                     spin_lock(&file_priv->table_lock);
> +                     idr_remove(&file_priv->object_idr, args->new_handle);
> +                     spin_unlock(&file_priv->table_lock);
> +                     goto out_unlock;
> +             }
> +
> +             drm_prime_remove_buf_handle(&file_priv->prime, args->handle);
> +     }
> +
> +     ret = 0;
> +
> +     spin_lock(&file_priv->table_lock);
> +     idr_remove(&file_priv->object_idr, args->handle);
> +     spin_unlock(&file_priv->table_lock);
> +
> +out_unlock:
> +     mutex_unlock(&file_priv->prime.lock);
> +
> +     return ret;
> +}
> +
>  /**
>   * drm_gem_open - initializes GEM file-private structures at devnode open 
> time
>   * @dev: drm_device which is being opened by userspace
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index b2b6a8e49dda..e9d5cdf7e033 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -85,6 +85,8 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, 
> void *data,
>  
>  void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
>  void drm_prime_destroy_file_private(struct drm_prime_file_private 
> *prime_fpriv);
> +int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
> +                          struct dma_buf *dma_buf, uint32_t handle);
>  void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
>                                uint32_t handle);
>  
> @@ -168,6 +170,8 @@ int drm_gem_close_ioctl(struct drm_device *dev, void 
> *data,
>                       struct drm_file *file_priv);
>  int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
>                       struct drm_file *file_priv);
> +int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
> +                             struct drm_file *file_priv);
>  int drm_gem_open_ioctl(struct drm_device *dev, void *data,
>                      struct drm_file *file_priv);
>  void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index f593dc569d31..d8a24875a7ba 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -653,6 +653,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>       DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 
> DRM_RENDER_ALLOW),
>       DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
>       DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
> +     DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, 
> DRM_RENDER_ALLOW),
>  
>       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0),
>  
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index bdb51c8f262e..1f2e858e5000 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -93,7 +93,7 @@ struct drm_prime_member {
>       struct rb_node handle_rb;
>  };
>  
> -static int drm_prime_add_buf_handle(struct drm_prime_file_private 
> *prime_fpriv,
> +int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
>                                   struct dma_buf *dma_buf, uint32_t handle)
>  {
>       struct drm_prime_member *member;
> @@ -190,8 +190,6 @@ void drm_prime_remove_buf_handle(struct 
> drm_prime_file_private *prime_fpriv,
>  {
>       struct rb_node *rb;
>  
> -     mutex_lock(&prime_fpriv->lock);
> -
>       rb = prime_fpriv->handles.rb_node;
>       while (rb) {
>               struct drm_prime_member *member;
> @@ -210,8 +208,6 @@ void drm_prime_remove_buf_handle(struct 
> drm_prime_file_private *prime_fpriv,
>                       rb = rb->rb_left;
>               }
>       }
> -
> -     mutex_unlock(&prime_fpriv->lock);
>  }
>  
>  void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index 7fba37b94401..e3940b657e16 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -625,6 +625,21 @@ struct drm_gem_open {
>       __u64 size;
>  };
>  
> +/**
> + * struct drm_gem_change_handle - Argument for &DRM_IOCTL_GEM_CHANGE_HANDLE 
> ioctl.
> + * @handle: The handle of a gem object.
> + * @new_handle: An available gem handle.
> + *
> + * This ioctl changes the handle of a GEM object to the specified one.
> + * The new handle must be unused. On success the old handle is closed
> + * and all further IOCTL should refer to the new handle only.
> + * Calls to DRM_IOCTL_PRIME_FD_TO_HANDLE will return the new handle.
> + */
> +struct drm_gem_change_handle {
> +     __u32 handle;
> +     __u32 new_handle;
> +};
> +
>  /**
>   * DRM_CAP_DUMB_BUFFER
>   *
> @@ -1305,6 +1320,14 @@ extern "C" {
>   */
>  #define DRM_IOCTL_SET_CLIENT_NAME    DRM_IOWR(0xD1, struct 
> drm_set_client_name)
>  
> +/**
> + * DRM_IOCTL_GEM_CHANGE_HANDLE - Move an object to a different handle
> + *
> + * Some applications (notably CRIU) need objects to have specific gem 
> handles.
> + * This ioctl changes the object at one gem handle to use a new gem handle.
> + */
> +#define DRM_IOCTL_GEM_CHANGE_HANDLE    DRM_IOWR(0xD2, struct 
> drm_gem_change_handle)
> +
>  /*
>   * Device specific ioctls should only be in their respective headers
>   * The device specific ioctl range is from 0x40 to 0x9f.

Reply via email to