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: Rebecca Schultz Zavin <rebecca@android.com> [jstultz: modified patch to apply to staging directory] Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
797a95c48c
commit
8d7ab9a9e1
1 changed files with 25 additions and 20 deletions
|
@ -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,
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
* 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)
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
__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)
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue