diff options
| author | Laura Abbott <lauraa@codeaurora.org> | 2014-09-23 19:28:31 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:04:13 -0700 |
| commit | cad09fc9a78940ffcb4d12911372ffd05d667de7 (patch) | |
| tree | c987baee96f117a85d38bd8e02bcd21bb72d17fb | |
| parent | 8f33c52993eeaf720b5ebf90fbf9018abb58cc58 (diff) | |
ion: Register with show_mem notification framework
Bugs in Ion clients are semi-common cause of out of memory
errors. Register with the show_mem notification framework
to let Ion dump out data for debugging. To avoid having to
take an excessive amount of locks, keep a running total of
allocated and potentially orphaned memory.
Change-Id: I52c31459d5bf975c67adb5f3fe17033c8e01d91b
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
| -rw-r--r-- | drivers/staging/android/ion/ion.c | 31 | ||||
| -rw-r--r-- | drivers/staging/android/ion/ion_priv.h | 2 | ||||
| -rw-r--r-- | drivers/staging/android/ion/ion_system_heap.c | 58 | ||||
| -rw-r--r-- | drivers/staging/android/ion/msm/msm_ion.c | 13 | ||||
| -rw-r--r-- | drivers/staging/android/ion/msm_ion_priv.h | 2 |
5 files changed, 90 insertions, 16 deletions
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 5cfa495909bc..93f626bc3dad 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -260,6 +260,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); + atomic_add(len, &heap->total_allocated); return buffer; err: @@ -277,6 +278,7 @@ void ion_buffer_destroy(struct ion_buffer *buffer) buffer->heap->ops->unmap_kernel(buffer->heap, buffer); buffer->heap->ops->unmap_dma(buffer->heap, buffer); + atomic_sub(buffer->size, &buffer->heap->total_allocated); buffer->heap->ops->free(buffer); vfree(buffer->pages); kfree(buffer); @@ -311,6 +313,9 @@ static int ion_buffer_put(struct ion_buffer *buffer) static void ion_buffer_add_to_handle(struct ion_buffer *buffer) { mutex_lock(&buffer->lock); + if (buffer->handle_count == 0) + atomic_add(buffer->size, &buffer->heap->total_handles); + buffer->handle_count++; mutex_unlock(&buffer->lock); } @@ -335,6 +340,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) task = current->group_leader; get_task_comm(buffer->task_comm, task); buffer->pid = task_pid_nr(task); + atomic_sub(buffer->size, &buffer->heap->total_handles); } mutex_unlock(&buffer->lock); } @@ -1708,6 +1714,31 @@ static const struct file_operations debug_heap_fops = { .release = single_release, }; +void show_ion_usage(struct ion_device *dev) +{ + struct ion_heap *heap; + + if (!down_read_trylock(&dev->lock)) { + pr_err("Ion output would deadlock, can't print debug information\n"); + return; + } + + pr_info("%16.s %16.s %16.s\n", "Heap name", "Total heap size", + "Total orphaned size"); + pr_info("---------------------------------\n"); + plist_for_each_entry(heap, &dev->heaps, node) { + pr_info("%16.s 0x%16.x 0x%16.x\n", + heap->name, atomic_read(&heap->total_allocated), + atomic_read(&heap->total_allocated) - + atomic_read(&heap->total_handles)); + if (heap->debug_show) + heap->debug_show(heap, NULL, 0); + + } + up_write(&dev->lock); +} + +#ifdef DEBUG_HEAP_SHRINKER static int debug_shrink_set(void *data, u64 val) { struct ion_heap *heap = data; diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index d724153f9824..4fa0daa2f637 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -198,6 +198,8 @@ struct ion_heap { struct task_struct *task; int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); + atomic_t total_allocated; + atomic_t total_handles; }; /** diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index f31098f023f4..1d84df3d0c38 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -399,31 +399,57 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, struct ion_system_heap *sys_heap = container_of(heap, struct ion_system_heap, heap); + bool use_seq = s != NULL; + unsigned long uncached_total = 0; + unsigned long cached_total = 0; + int i; for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->uncached_pools[i]; - seq_printf(s, - "%d order %u highmem pages in uncached pool = %lu total\n", - pool->high_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->high_count); - seq_printf(s, - "%d order %u lowmem pages in uncached pool = %lu total\n", - pool->low_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->low_count); + if (use_seq) { + seq_printf(s, + "%d order %u highmem pages in uncached pool = %lu total\n", + pool->high_count, pool->order, + (1 << pool->order) * PAGE_SIZE * + pool->high_count); + seq_printf(s, + "%d order %u lowmem pages in uncached pool = %lu total\n", + pool->low_count, pool->order, + (1 << pool->order) * PAGE_SIZE * + pool->low_count); + } else { + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + uncached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; + } + } for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->cached_pools[i]; - seq_printf(s, - "%d order %u highmem pages in cached pool = %lu total\n", - pool->high_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->high_count); - seq_printf(s, - "%d order %u lowmem pages in cached pool = %lu total\n", - pool->low_count, pool->order, - (1 << pool->order) * PAGE_SIZE * pool->low_count); + if (use_seq) { + seq_printf(s, + "%d order %u highmem pages in cached pool = %lu total\n", + pool->high_count, pool->order, + (1 << pool->order) * PAGE_SIZE * pool->high_count); + seq_printf(s, + "%d order %u lowmem pages in cached pool = %lu total\n", + pool->low_count, pool->order, + (1 << pool->order) * PAGE_SIZE * + pool->low_count); + } else { + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->high_count; + cached_total += (1 << pool->order) * PAGE_SIZE * + pool->low_count; + } } + if (!use_seq) + pr_info("uncached pool total = %lu cached pool total %lu\n", + uncached_total, cached_total); + return 0; } diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c index 7330256d9fc7..46186ea07730 100644 --- a/drivers/staging/android/ion/msm/msm_ion.c +++ b/drivers/staging/android/ion/msm/msm_ion.c @@ -109,6 +109,17 @@ static struct ion_heap_desc ion_heap_meta[] = { }; #endif +static int msm_ion_lowmem_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + show_ion_usage(idev); + return 0; +} + +static struct notifier_block msm_ion_nb = { + .notifier_call = msm_ion_lowmem_notifier, +}; + struct ion_client *msm_ion_client_create(const char *name) { /* @@ -949,6 +960,8 @@ static int msm_ion_probe(struct platform_device *pdev) * completely until Ion is setup */ idev = new_dev; + + show_mem_notifier_register(&msm_ion_nb); return 0; freeheaps: diff --git a/drivers/staging/android/ion/msm_ion_priv.h b/drivers/staging/android/ion/msm_ion_priv.h index a40f78023b3a..4ff76aa5cc60 100644 --- a/drivers/staging/android/ion/msm_ion_priv.h +++ b/drivers/staging/android/ion/msm_ion_priv.h @@ -123,4 +123,6 @@ int ion_heap_allow_handle_secure(enum ion_heap_type type); */ struct sg_table *ion_create_chunked_sg_table(phys_addr_t buffer_base, size_t chunk_size, size_t total_size); + +void show_ion_usage(struct ion_device *dev); #endif /* _MSM_ION_PRIV_H */ |
