[AMD Official Use Only - AMD Internal Distribution Only]

-----Original Message-----
From: dri-devel <dri-devel-boun...@lists.freedesktop.org> On Behalf Of David 
Francis
Sent: Friday, July 11, 2025 10:54 PM
To: dri-devel@lists.freedesktop.org
Cc: tvrtko.ursu...@igalia.com; Kuehling, Felix <felix.kuehl...@amd.com>; Yat 
Sin, David <david.yat...@amd.com>; Freehill, Chris <chris.freeh...@amd.com>; 
Koenig, Christian <christian.koe...@amd.com>; dcostant...@meta.com; 
sruff...@meta.com; sim...@ffwll.ch; mrip...@kernel.org; tzimmerm...@suse.de; 
Francis, David <david.fran...@amd.com>
Subject: [PATCH 1/2] drm: Add DRM prime interface to reassign GEM handle

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/

Signed-off-by: David Francis <david.fran...@amd.com>
---
 drivers/gpu/drm/drm_gem.c      | 54 ++++++++++++++++++++++++++++++++++
 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, 83 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 
c6240bab3fa5..3166230d0119 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,55 @@ 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);
+       }
+
           Added ret = 0 before out_unlock to ensure proper return value
        ret = 0;

        Thanks
        Jesse
+       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.
--
2.34.1

Reply via email to