diff options
Diffstat (limited to 'drivers/staging/android')
| -rw-r--r-- | drivers/staging/android/ion/ion.c | 58 | ||||
| -rw-r--r-- | drivers/staging/android/ion/ion_priv.h | 14 |
2 files changed, 72 insertions, 0 deletions
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index e52522c11c5..6ba2c39f793 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -228,6 +228,37 @@ static int ion_buffer_put(struct ion_buffer *buffer) return kref_put(&buffer->ref, ion_buffer_destroy); } +static void ion_buffer_add_to_handle(struct ion_buffer *buffer) +{ + mutex_lock(&buffer->dev->lock); + buffer->handle_count++; + mutex_unlock(&buffer->dev->lock); +} + +static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) +{ + /* + * when a buffer is removed from a handle, if it is not in + * any other handles, copy the taskcomm and the pid of the + * process it's being removed from into the buffer. At this + * point there will be no way to track what processes this buffer is + * being used by, it only exists as a dma_buf file descriptor. + * The taskcomm and pid can provide a debug hint as to where this fd + * is in the system + */ + mutex_lock(&buffer->dev->lock); + buffer->handle_count--; + BUG_ON(buffer->handle_count < 0); + if (!buffer->handle_count) { + struct task_struct *task; + + task = current->group_leader; + get_task_comm(buffer->task_comm, task); + buffer->pid = task_pid_nr(task); + } + mutex_unlock(&buffer->dev->lock); +} + static struct ion_handle *ion_handle_create(struct ion_client *client, struct ion_buffer *buffer) { @@ -240,6 +271,7 @@ static struct ion_handle *ion_handle_create(struct ion_client *client, RB_CLEAR_NODE(&handle->node); handle->client = client; ion_buffer_get(buffer); + ion_buffer_add_to_handle(buffer); handle->buffer = buffer; return handle; @@ -261,7 +293,9 @@ static void ion_handle_destroy(struct kref *kref) if (!RB_EMPTY_NODE(&handle->node)) rb_erase(&handle->node, &client->handles); + ion_buffer_remove_from_handle(buffer); ion_buffer_put(buffer); + kfree(handle); } @@ -1141,8 +1175,11 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) struct ion_heap *heap = s->private; struct ion_device *dev = heap->dev; struct rb_node *n; + size_t total_size = 0; + size_t total_orphaned_size = 0; seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); + seq_printf(s, "----------------------------------------------------\n"); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, @@ -1161,6 +1198,27 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) client->pid, size); } } + seq_printf(s, "----------------------------------------------------\n"); + seq_printf(s, "orphaned allocations (info is from last known client):" + "\n"); + mutex_lock(&dev->lock); + for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { + struct ion_buffer *buffer = rb_entry(n, struct ion_buffer, + node); + if (buffer->heap->type == heap->type) + total_size += buffer->size; + if (!buffer->handle_count) { + seq_printf(s, "%16.s %16u %16u\n", buffer->task_comm, + buffer->pid, buffer->size); + total_orphaned_size += buffer->size; + } + } + mutex_unlock(&dev->lock); + seq_printf(s, "----------------------------------------------------\n"); + seq_printf(s, "%16.s %16u\n", "total orphaned", + total_orphaned_size); + seq_printf(s, "%16.s %16u\n", "total ", total_size); + return 0; } diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 406d1f43bf1..dabe1e87bed 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -21,6 +21,7 @@ #include <linux/mm_types.h> #include <linux/mutex.h> #include <linux/rbtree.h> +#include <linux/sched.h> #include "ion.h" @@ -43,6 +44,15 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @vaddr: the kenrel mapping if kmap_cnt is not zero * @dmap_cnt: number of times the buffer is mapped for dma * @sg_table: the sg table for the buffer if dmap_cnt is not zero + * @dirty: bitmask representing which pages of this buffer have + * been dirtied by the cpu and need cache maintenance + * before dma + * @vmas: list of vma's mapping this buffer + * @handle_count: count of handles referencing this buffer + * @task_comm: taskcomm of last client to reference this buffer in a + * handle, used for debugging + * @pid: pid of last client to reference this buffer in a + * handle, used for debugging */ struct ion_buffer { struct kref ref; @@ -62,6 +72,10 @@ struct ion_buffer { struct sg_table *sg_table; unsigned long *dirty; struct list_head vmas; + /* used to track orphaned buffers */ + int handle_count; + char task_comm[TASK_COMM_LEN]; + pid_t pid; }; /** |
