summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaura Abbott <lauraa@codeaurora.org>2014-09-23 19:28:31 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:04:13 -0700
commitcad09fc9a78940ffcb4d12911372ffd05d667de7 (patch)
treec987baee96f117a85d38bd8e02bcd21bb72d17fb
parent8f33c52993eeaf720b5ebf90fbf9018abb58cc58 (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.c31
-rw-r--r--drivers/staging/android/ion/ion_priv.h2
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c58
-rw-r--r--drivers/staging/android/ion/msm/msm_ion.c13
-rw-r--r--drivers/staging/android/ion/msm_ion_priv.h2
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 */