CRIU restore of drm buffer objects requires the ability to create a buffer object with a specific gem handle.
Add function drm_prime_change_buf_handle to change the gem handle of a specified buffer object. This function calls drm_gem_object_release_handle. drm_gem_object_release_handle is an internal function with one caller; make it not acquire the prime lock. Signed-off-by: David Francis <david.fran...@amd.com> --- drivers/gpu/drm/drm_gem.c | 5 ++++ drivers/gpu/drm/drm_prime.c | 47 +++++++++++++++++++++++++++++++++---- include/drm/drm_prime.h | 2 ++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index ee811764c3df..f56eeed808d2 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); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 0e3f8adf162f..08205b291825 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -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) @@ -1084,3 +1080,46 @@ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) dma_buf_put(dma_buf); } EXPORT_SYMBOL(drm_prime_gem_destroy); + +/** + * drm_prime_change_buf_handle - function to change the gem handle of a bo + * @file_priv: drm file-private structure + * @gem_obj: gem object whose handle should be changed + * @newhandle: handle to change to + * + * Will fail if the gem object cannot be found or if the new handle + * is already in use. + */ +int drm_prime_change_buf_handle(struct drm_file *file_priv, struct drm_gem_object *gem_obj, int newhandle) +{ + int oldhandle = -1; + int ret; + + mutex_lock(&file_priv->prime.lock); + + ret = drm_prime_lookup_buf_handle(&file_priv->prime, gem_obj->dma_buf, &oldhandle); + if (ret < 0) + goto out_unlock; + + drm_prime_remove_buf_handle(&file_priv->prime, oldhandle); + + spin_lock(&file_priv->table_lock); + + idr_remove(&file_priv->object_idr, oldhandle); + ret = idr_alloc(&file_priv->object_idr, gem_obj, newhandle, newhandle + 1, GFP_NOWAIT); + + spin_unlock(&file_priv->table_lock); + + if (ret < 0) + goto out_unlock; + + ret = drm_prime_add_buf_handle(&file_priv->prime, gem_obj->dma_buf, newhandle); + if (ret < 0) + goto out_unlock; + +out_unlock: + mutex_unlock(&file_priv->prime.lock); + + return ret; +} +EXPORT_SYMBOL(drm_prime_change_buf_handle); \ No newline at end of file diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index fa085c44d4ca..5a9288493dd7 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -112,5 +112,7 @@ int drm_prime_sg_to_page_array(struct sg_table *sgt, struct page **pages, int max_pages); int drm_prime_sg_to_dma_addr_array(struct sg_table *sgt, dma_addr_t *addrs, int max_pages); +int drm_prime_change_buf_handle(struct drm_file *file_priv, + struct drm_gem_object *gem_obj, int newhandle); #endif /* __DRM_PRIME_H__ */ -- 2.34.1