diff options
Diffstat (limited to 'drivers/gpu/drm/drm_gem.c')
| -rw-r--r-- | drivers/gpu/drm/drm_gem.c | 74 | 
1 files changed, 64 insertions, 10 deletions
| diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 1e659d2660f7..ac0524595bd6 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -212,6 +212,46 @@ void drm_gem_private_object_fini(struct drm_gem_object *obj)  }  EXPORT_SYMBOL(drm_gem_private_object_fini); +static void drm_gem_object_handle_get(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; + +	drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock)); + +	if (obj->handle_count++ == 0) +		drm_gem_object_get(obj); +} + +/** + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any + * @obj: GEM object + * + * Acquires a reference on the GEM buffer object's handle. Required to keep + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() + * to release the reference. Does nothing if the buffer object has no handle. + * + * Returns: + * True if a handle exists, or false otherwise + */ +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; + +	guard(mutex)(&dev->object_name_lock); + +	/* +	 * First ref taken during GEM object creation, if any. Some +	 * drivers set up internal framebuffers with GEM objects that +	 * do not have a GEM handle. Hence, this counter can be zero. +	 */ +	if (!obj->handle_count) +		return false; + +	drm_gem_object_handle_get(obj); + +	return true; +} +  /**   * drm_gem_object_handle_free - release resources bound to userspace handles   * @obj: GEM object to clean up. @@ -242,20 +282,26 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)  	}  } -static void -drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) +/** + * drm_gem_object_handle_put_unlocked - releases reference on user-space handle + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases + * the GEM buffer object and associated dma-buf objects. + */ +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)  {  	struct drm_device *dev = obj->dev;  	bool final = false; -	if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) +	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))  		return;  	/* -	* Must bump handle count first as this may be the last -	* ref, in which case the object would disappear before we -	* checked for a name -	*/ +	 * Must bump handle count first as this may be the last +	 * ref, in which case the object would disappear before +	 * we checked for a name. +	 */  	mutex_lock(&dev->object_name_lock);  	if (--obj->handle_count == 0) { @@ -279,6 +325,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)  	struct drm_file *file_priv = data;  	struct drm_gem_object *obj = ptr; +	if (drm_WARN_ON(obj->dev, !data)) +		return 0; +  	if (obj->funcs->close)  		obj->funcs->close(obj, file_priv); @@ -389,8 +438,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  	int ret;  	WARN_ON(!mutex_is_locked(&dev->object_name_lock)); -	if (obj->handle_count++ == 0) -		drm_gem_object_get(obj); + +	drm_gem_object_handle_get(obj);  	/*  	 * Get the user-visible handle using idr.  Preload and perform @@ -399,7 +448,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  	idr_preload(GFP_KERNEL);  	spin_lock(&file_priv->table_lock); -	ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT); +	ret = idr_alloc(&file_priv->object_idr, NULL, 1, 0, GFP_NOWAIT);  	spin_unlock(&file_priv->table_lock);  	idr_preload_end(); @@ -420,6 +469,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  			goto err_revoke;  	} +	/* mirrors drm_gem_handle_delete to avoid races */ +	spin_lock(&file_priv->table_lock); +	obj = idr_replace(&file_priv->object_idr, obj, handle); +	WARN_ON(obj != NULL); +	spin_unlock(&file_priv->table_lock);  	*handlep = handle;  	return 0; | 
