On 5/21/25 16:06, 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. > > Signed-off-by: David Francis <david.fran...@amd.com> > --- > drivers/gpu/drm/drm_gem.c | 52 ++++++++++++++++++++++++++++++++++ > 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 | 17 +++++++++++ > 5 files changed, 75 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c > index c6240bab3fa5..d388bbb7a9de 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); > @@ -888,6 +893,53 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, > return ret; > } > > +/** > + * drm_gem_open_ioctl - implementation of the GEM_CHANGE_HANDLE ioctl > + * @dev: drm_device > + * @data: ioctl data > + * @file_priv: drm file-private structure > + * > + * find the object at the specified gem handle. Remove it from that handle, > and assign it > + * the specified new handle. > + */ > +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; > + > + obj = drm_gem_object_lookup(file_priv, args->handle); > + if (!obj) > + return -ENOENT; > + > + if (args->handle == args->new_handle) > + return 0; > + > + get_dma_buf(obj->dma_buf);
That is unecessary now that the new handle is made valid before the old one is removed. > + 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); > + if (ret < 0) > + goto out_unlock; > + > + ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, > args->new_handle); That function allocates memory and so can't easily be called in atomic context. In other words you need to drop the file_priv->table_lock spinlock before calling it. > + if (ret < 0) > + goto out_unlock; > + > + drm_prime_remove_buf_handle(&file_priv->prime, args->handle); > + > + idr_remove(&file_priv->object_idr, args->handle); Then re-acquire the spinlock before calling this here. Regards, Christian. > + > +out_unlock: > + spin_unlock(&file_priv->table_lock); > + mutex_unlock(&file_priv->prime.lock); > + dma_buf_put(obj->dma_buf); > + > + return ret; > +} > + > /** > * drm_gem_open_ioctl - implementation of the GEM_OPEN ioctl > * @dev: drm_device > 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..84c819c171d2 100644 > --- a/include/uapi/drm/drm.h > +++ b/include/uapi/drm/drm.h > @@ -625,6 +625,15 @@ struct drm_gem_open { > __u64 size; > }; > > +/* DRM_IOCTL_GEM_CHANGE_HANDLE ioctl argument type */ > +struct drm_gem_change_handle { > + /** Current handle of object */ > + __u32 handle; > + > + /** Handle to change that object to */ > + __u32 new_handle; > +}; > + > /** > * DRM_CAP_DUMB_BUFFER > * > @@ -1305,6 +1314,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.