diff options
author | Eric Anholt <eric@anholt.net> | 2013-01-08 14:29:58 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2013-01-08 16:00:42 -0800 |
commit | af3f46c2c9e0604d5459423b60b7e7455b61a29c (patch) | |
tree | e41f6c5bcd186331001bbb88d4903337eb60388e | |
parent | d0a69ef2f71306dd64a31cfe6d10b335b0a5d83f (diff) |
drm/i915: Use an ida instead of an idr, and maintain our own pointer table.
The multi-layer nature of the idr is too expensive for our purposes,
so just use the ida code for number allocation (should be faster than
walking our array, since it's a bitmask)
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/drm_gem.c | 139 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 | ||||
-rw-r--r-- | include/drm/drmP.h | 10 |
3 files changed, 84 insertions, 67 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index b9046089e9e..dddb373af96 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -223,27 +223,25 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) struct drm_device *dev; struct drm_gem_object *obj; - /* This is gross. The idr system doesn't let us try a delete and - * return an error code. It just spews if you fail at deleting. - * So, we have to grab a lock around finding the object and then - * doing the delete on it and dropping the refcount, or the user - * could race us to double-decrement the refcount and cause a - * use-after-free later. Given the frequency of our handle lookups, - * we may want to use ida for number allocation and a hash table - * for the pointers, anyway. - */ mutex_lock(&filp->table_lock); - /* Check if we currently have a reference on the object */ - obj = idr_find(&filp->object_idr, handle); - if (obj == NULL) { + if (handle > filp->object_table_size) { mutex_unlock(&filp->table_lock); return -EINVAL; } + + obj = filp->object_table[handle]; + if (!obj) { + mutex_unlock(&filp->table_lock); + return -EINVAL; + } + dev = obj->dev; /* Release reference and decrement refcount. */ - idr_remove(&filp->object_idr, handle); + filp->object_table[handle] = NULL; + ida_simple_remove(&filp->object_ida, handle); + mutex_unlock(&filp->table_lock); drm_gem_remove_prime_handles(obj, filp); @@ -267,31 +265,40 @@ drm_gem_handle_create(struct drm_file *file_priv, u32 *handlep) { struct drm_device *dev = obj->dev; - int ret; + int ret, handle; - /* - * Get the user-visible handle using idr. - */ -again: - /* ensure there is space available to allocate a handle */ - if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) - return -ENOMEM; + /* Get the user-visible handle using ida. */ + ret = ida_simple_get(&file_priv->object_ida, 1, 0, GFP_KERNEL); + if (ret < 0) + return ret; + handle = ret; - /* do the allocation under our spinlock */ mutex_lock(&file_priv->table_lock); - ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep); - mutex_unlock(&file_priv->table_lock); - if (ret == -EAGAIN) - goto again; - else if (ret) - return ret; + /* Resize the table of object pointers if necessary. */ + if (file_priv->object_table_size <= handle) { + u32 new_table_size = file_priv->object_table_size * 2; + void *new_table = vzalloc(new_table_size * sizeof(void *)); + if (!new_table) { + ida_simple_remove(&file_priv->object_ida, handle); + mutex_unlock(&file_priv->table_lock); + return -ENOMEM; + } + memcpy(new_table, file_priv->object_table, + file_priv->object_table_size * sizeof(void *)); + vfree(file_priv->object_table); + file_priv->object_table = new_table; + file_priv->object_table_size = new_table_size; + } + file_priv->object_table[handle] = obj; + *handlep = handle; drm_gem_object_handle_reference(obj); + mutex_unlock(&file_priv->table_lock); if (dev->driver->gem_open_object) { ret = dev->driver->gem_open_object(obj, file_priv); if (ret) { - drm_gem_handle_delete(file_priv, *handlep); + drm_gem_handle_delete(file_priv, handle); return ret; } } @@ -388,20 +395,30 @@ out_free_list: } EXPORT_SYMBOL(drm_gem_create_mmap_offset); -/** Returns a reference to the object named by the handle. */ +/** + * Returns the pointer to the object named by handle. + * + * No reference is taken on the object, and the call must have the + * table_lock held. + */ +struct drm_gem_object * +drm_gem_object_find(struct drm_file *filp, u32 handle) +{ + if (filp->object_table_size > handle) + return filp->object_table[handle]; + else + return NULL; +} +EXPORT_SYMBOL(drm_gem_object_find); + struct drm_gem_object * drm_gem_object_lookup_locked(struct drm_file *filp, u32 handle) { struct drm_gem_object *obj; - /* Check if we currently have a reference on the object */ - obj = idr_find(&filp->object_idr, handle); - if (obj == NULL) { - mutex_unlock(&filp->table_lock); - return NULL; - } - - drm_gem_object_reference(obj); + obj = drm_gem_object_find(filp, handle); + if (obj) + drm_gem_object_reference(obj); return obj; } @@ -535,29 +552,10 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, void drm_gem_open(struct drm_device *dev, struct drm_file *file_private) { - idr_init(&file_private->object_idr); + ida_init(&file_private->object_ida); mutex_init(&file_private->table_lock); -} - -/** - * Called at device close to release the file's - * handle references on objects. - */ -static int -drm_gem_object_release_handle(int id, void *ptr, void *data) -{ - struct drm_file *file_priv = data; - struct drm_gem_object *obj = ptr; - struct drm_device *dev = obj->dev; - - drm_gem_remove_prime_handles(obj, file_priv); - - if (dev->driver->gem_close_object) - dev->driver->gem_close_object(obj, file_priv); - - drm_gem_object_handle_unreference_unlocked(obj); - - return 0; + file_private->object_table_size = 16; + file_private->object_table = vzalloc(16 * sizeof(void *)); } /** @@ -568,11 +566,24 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) 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); + u32 i; + + for (i = 0; i < file_private->object_table_size; i++) { + struct drm_gem_object *obj = file_private->object_table[i]; + + if (!obj) + continue; + + drm_gem_remove_prime_handles(obj, file_private); + + if (dev->driver->gem_close_object) + dev->driver->gem_close_object(obj, file_private); + + drm_gem_object_handle_unreference_unlocked(obj); + + } - idr_remove_all(&file_private->object_idr); - idr_destroy(&file_private->object_idr); + ida_destroy(&file_private->object_ida); } void diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 23a8a51a7ea..a2245be7d82 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -54,7 +54,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, /* Note that objects can't disappear from the idr while we * hold the struct_mutex, and thus can't be unreferenced. */ - target_obj = idr_find(&file->object_idr, reloc->target_handle); + target_obj = drm_gem_object_find(file, reloc->target_handle); if (unlikely(target_obj == NULL)) return -ENOENT; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 96f582d840d..4d93bb4aee2 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -435,9 +435,12 @@ struct drm_file { struct drm_minor *minor; unsigned long lock_count; + /** ida used to choose an object handle. */ + struct ida object_ida; /** Mapping of mm object handles to object pointers. */ - struct idr object_idr; - /** Lock for synchronization of access to object_idr. */ + struct drm_gem_object **object_table; + u32 object_table_size; + /** Lock for synchronization of access to object_table/object_ida. */ struct mutex table_lock; struct file *filp; @@ -1701,6 +1704,9 @@ struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, u32 handle); struct drm_gem_object *drm_gem_object_lookup_locked(struct drm_file *filp, u32 handle); +struct drm_gem_object *drm_gem_object_find(struct drm_file *filp, + u32 handle); + 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, |