Commit 8d7ab9a9 authored by Rebecca Schultz Zavin's avatar Rebecca Schultz Zavin Committed by Greg Kroah-Hartman

gpu: ion: Refactor locking

Removes contention for lock between allocate and free by reducing
the length of time the lock is held for.  Split out a seperate
lock to protect the list of heaps and replace it with a rwsem since
the list will most likely only be updated during initialization.
Signed-off-by: default avatarRebecca Schultz Zavin <rebecca@android.com>
[jstultz: modified patch to apply to staging directory]
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 797a95c4
...@@ -39,14 +39,16 @@ ...@@ -39,14 +39,16 @@
* struct ion_device - the metadata of the ion device node * struct ion_device - the metadata of the ion device node
* @dev: the actual misc device * @dev: the actual misc device
* @buffers: an rb tree of all the existing buffers * @buffers: an rb tree of all the existing buffers
* @lock: lock protecting the buffers & heaps trees * @buffer_lock: lock protecting the tree of buffers
* @lock: rwsem protecting the tree of heaps and clients
* @heaps: list of all the heaps in the system * @heaps: list of all the heaps in the system
* @user_clients: list of all the clients created from userspace * @user_clients: list of all the clients created from userspace
*/ */
struct ion_device { struct ion_device {
struct miscdevice dev; struct miscdevice dev;
struct rb_root buffers; struct rb_root buffers;
struct mutex lock; struct mutex buffer_lock;
struct rw_semaphore lock;
struct rb_root heaps; struct rb_root heaps;
long (*custom_ioctl) (struct ion_client *client, unsigned int cmd, long (*custom_ioctl) (struct ion_client *client, unsigned int cmd,
unsigned long arg); unsigned long arg);
...@@ -205,7 +207,9 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, ...@@ -205,7 +207,9 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
cached mapping that mapping has been invalidated */ cached mapping that mapping has been invalidated */
for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
sg_dma_address(sg) = sg_phys(sg); sg_dma_address(sg) = sg_phys(sg);
mutex_lock(&dev->buffer_lock);
ion_buffer_add(dev, buffer); ion_buffer_add(dev, buffer);
mutex_unlock(&dev->buffer_lock);
return buffer; return buffer;
err: err:
...@@ -224,9 +228,9 @@ static void ion_buffer_destroy(struct kref *kref) ...@@ -224,9 +228,9 @@ static void ion_buffer_destroy(struct kref *kref)
buffer->heap->ops->unmap_kernel(buffer->heap, buffer); buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
buffer->heap->ops->unmap_dma(buffer->heap, buffer); buffer->heap->ops->unmap_dma(buffer->heap, buffer);
buffer->heap->ops->free(buffer); buffer->heap->ops->free(buffer);
mutex_lock(&dev->lock); mutex_lock(&dev->buffer_lock);
rb_erase(&buffer->node, &dev->buffers); rb_erase(&buffer->node, &dev->buffers);
mutex_unlock(&dev->lock); mutex_unlock(&dev->buffer_lock);
if (buffer->flags & ION_FLAG_CACHED) if (buffer->flags & ION_FLAG_CACHED)
kfree(buffer->dirty); kfree(buffer->dirty);
kfree(buffer); kfree(buffer);
...@@ -244,9 +248,9 @@ static int ion_buffer_put(struct ion_buffer *buffer) ...@@ -244,9 +248,9 @@ static int ion_buffer_put(struct ion_buffer *buffer)
static void ion_buffer_add_to_handle(struct ion_buffer *buffer) static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
{ {
mutex_lock(&buffer->dev->lock); mutex_lock(&buffer->lock);
buffer->handle_count++; buffer->handle_count++;
mutex_unlock(&buffer->dev->lock); mutex_unlock(&buffer->lock);
} }
static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) static void ion_buffer_remove_from_handle(struct ion_buffer *buffer)
...@@ -260,7 +264,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) ...@@ -260,7 +264,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer)
* The taskcomm and pid can provide a debug hint as to where this fd * The taskcomm and pid can provide a debug hint as to where this fd
* is in the system * is in the system
*/ */
mutex_lock(&buffer->dev->lock); mutex_lock(&buffer->lock);
buffer->handle_count--; buffer->handle_count--;
BUG_ON(buffer->handle_count < 0); BUG_ON(buffer->handle_count < 0);
if (!buffer->handle_count) { if (!buffer->handle_count) {
...@@ -270,7 +274,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) ...@@ -270,7 +274,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer)
get_task_comm(buffer->task_comm, task); get_task_comm(buffer->task_comm, task);
buffer->pid = task_pid_nr(task); buffer->pid = task_pid_nr(task);
} }
mutex_unlock(&buffer->dev->lock); mutex_unlock(&buffer->lock);
} }
static struct ion_handle *ion_handle_create(struct ion_client *client, static struct ion_handle *ion_handle_create(struct ion_client *client,
...@@ -403,7 +407,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, ...@@ -403,7 +407,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
len = PAGE_ALIGN(len); len = PAGE_ALIGN(len);
mutex_lock(&dev->lock); down_read(&dev->lock);
for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) { for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
struct ion_heap *heap = rb_entry(n, struct ion_heap, node); struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
/* if the client doesn't support this heap type */ /* if the client doesn't support this heap type */
...@@ -416,7 +420,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, ...@@ -416,7 +420,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
if (!IS_ERR_OR_NULL(buffer)) if (!IS_ERR_OR_NULL(buffer))
break; break;
} }
mutex_unlock(&dev->lock); up_read(&dev->lock);
if (buffer == NULL) if (buffer == NULL)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -662,7 +666,7 @@ struct ion_client *ion_client_create(struct ion_device *dev, ...@@ -662,7 +666,7 @@ struct ion_client *ion_client_create(struct ion_device *dev,
client->task = task; client->task = task;
client->pid = pid; client->pid = pid;
mutex_lock(&dev->lock); down_write(&dev->lock);
p = &dev->clients.rb_node; p = &dev->clients.rb_node;
while (*p) { while (*p) {
parent = *p; parent = *p;
...@@ -680,7 +684,7 @@ struct ion_client *ion_client_create(struct ion_device *dev, ...@@ -680,7 +684,7 @@ struct ion_client *ion_client_create(struct ion_device *dev,
client->debug_root = debugfs_create_file(debug_name, 0664, client->debug_root = debugfs_create_file(debug_name, 0664,
dev->debug_root, client, dev->debug_root, client,
&debug_client_fops); &debug_client_fops);
mutex_unlock(&dev->lock); up_write(&dev->lock);
return client; return client;
} }
...@@ -696,12 +700,12 @@ void ion_client_destroy(struct ion_client *client) ...@@ -696,12 +700,12 @@ void ion_client_destroy(struct ion_client *client)
node); node);
ion_handle_destroy(&handle->ref); ion_handle_destroy(&handle->ref);
} }
mutex_lock(&dev->lock); down_write(&dev->lock);
if (client->task) if (client->task)
put_task_struct(client->task); put_task_struct(client->task);
rb_erase(&client->node, &dev->clients); rb_erase(&client->node, &dev->clients);
debugfs_remove_recursive(client->debug_root); debugfs_remove_recursive(client->debug_root);
mutex_unlock(&dev->lock); up_write(&dev->lock);
kfree(client); kfree(client);
} }
...@@ -1220,7 +1224,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) ...@@ -1220,7 +1224,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
seq_printf(s, "----------------------------------------------------\n"); seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "orphaned allocations (info is from last known client):" seq_printf(s, "orphaned allocations (info is from last known client):"
"\n"); "\n");
mutex_lock(&dev->lock); mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer, struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
node); node);
...@@ -1233,7 +1237,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) ...@@ -1233,7 +1237,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
total_orphaned_size += buffer->size; total_orphaned_size += buffer->size;
} }
} }
mutex_unlock(&dev->lock); mutex_unlock(&dev->buffer_lock);
seq_printf(s, "----------------------------------------------------\n"); seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16u\n", "total orphaned", seq_printf(s, "%16.s %16u\n", "total orphaned",
total_orphaned_size); total_orphaned_size);
...@@ -1270,7 +1274,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) ...@@ -1270,7 +1274,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
__func__); __func__);
heap->dev = dev; heap->dev = dev;
mutex_lock(&dev->lock); down_write(&dev->lock);
while (*p) { while (*p) {
parent = *p; parent = *p;
entry = rb_entry(parent, struct ion_heap, node); entry = rb_entry(parent, struct ion_heap, node);
...@@ -1291,7 +1295,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) ...@@ -1291,7 +1295,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
debugfs_create_file(heap->name, 0664, dev->debug_root, heap, debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
&debug_heap_fops); &debug_heap_fops);
end: end:
mutex_unlock(&dev->lock); up_write(&dev->lock);
} }
struct ion_device *ion_device_create(long (*custom_ioctl) struct ion_device *ion_device_create(long (*custom_ioctl)
...@@ -1322,7 +1326,8 @@ struct ion_device *ion_device_create(long (*custom_ioctl) ...@@ -1322,7 +1326,8 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
idev->custom_ioctl = custom_ioctl; idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT; idev->buffers = RB_ROOT;
mutex_init(&idev->lock); mutex_init(&idev->buffer_lock);
init_rwsem(&idev->lock);
idev->heaps = RB_ROOT; idev->heaps = RB_ROOT;
idev->clients = RB_ROOT; idev->clients = RB_ROOT;
return idev; return idev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment