mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-28 07:54:36 -05:00
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.Francis@amd.com/ v2 - Move documentation to UAPI headers v3 - Always return 0 on success Signed-off-by: David Francis <David.Francis@amd.com> Acked-by: Felix Kuehling <felix.kuehling@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Christian König <christian.koenig@amd.com> Link: https://lore.kernel.org/r/20250717143556.857893-2-David.Francis@amd.com
This commit is contained in:
committed by
Christian König
parent
b9a572f471
commit
53096728b8
@@ -283,7 +283,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);
|
||||
@@ -934,6 +939,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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -1309,6 +1324,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.
|
||||
|
||||
Reference in New Issue
Block a user