--- x/drivers/gpu/drm/drm_gem.c +++ y/drivers/gpu/drm/drm_gem.c @@ -401,22 +401,20 @@ drm_gem_handle_delete(struct drm_file *f { struct drm_gem_object *obj; + mutex_lock(&filp->prime.lock); spin_lock(&filp->table_lock); /* Check if we currently have a reference on the object */ - obj = idr_replace(&filp->object_idr, NULL, handle); + obj = idr_find(&filp->object_idr, handle); + idr_remove(&filp->object_idr, handle); spin_unlock(&filp->table_lock); + mutex_unlock(&filp->prime.lock); + if (IS_ERR_OR_NULL(obj)) return -EINVAL; - /* Release driver's reference and decrement refcount. */ drm_gem_object_release_handle(handle, obj, filp); - /* And finally make the handle available for future allocations. */ - spin_lock(&filp->table_lock); - idr_remove(&filp->object_idr, handle); - spin_unlock(&filp->table_lock); - return 0; } EXPORT_SYMBOL(drm_gem_handle_delete); @@ -1012,17 +1010,20 @@ int drm_gem_change_handle_ioctl(struct d return -EINVAL; handle = args->new_handle; + mutex_lock(&file_priv->prime.lock); + obj = drm_gem_object_lookup(file_priv, args->handle); - if (!obj) + if (!obj) { + mutex_unlock(&file_priv->prime.lock); return -ENOENT; + } if (args->handle == handle) { + mutex_unlock(&file_priv->prime.lock); ret = 0; goto out; } - mutex_lock(&file_priv->prime.lock); - spin_lock(&file_priv->table_lock); ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1, GFP_NOWAIT); @@ -1085,8 +1086,22 @@ drm_gem_open(struct drm_device *dev, str void drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { - idr_for_each(&file_private->object_idr, - &drm_gem_object_release_handle, file_private); + struct drm_gem_object *obj; + int id; + + for (;;) { + id = 0; + mutex_lock(&file_private->prime.lock); + spin_lock(&file_private->table_lock); + obj = idr_get_next(&file_private->object_idr, &id); + if (obj) + idr_remove(&file_private->object_idr, id); + spin_unlock(&file_private->table_lock); + mutex_unlock(&file_private->prime.lock); + if (!obj) + break; + drm_gem_object_release_handle(id, obj, file_private); + } idr_destroy(&file_private->object_idr); }