Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2da88f4 authored by Laura Abbott's avatar Laura Abbott
Browse files

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: default avatarLaura Abbott <lauraa@codeaurora.org>
parent f3f7bb2e
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -261,6 +261,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:
@@ -280,6 +281,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);
	if (buffer->pages)
		vfree(buffer->pages);
@@ -315,6 +317,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);
}
@@ -339,6 +344,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);
}
@@ -1700,6 +1706,30 @@ 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)
{
+2 −0
Original line number Diff line number Diff line
@@ -194,6 +194,8 @@ struct ion_heap {
	wait_queue_head_t waitqueue;
	struct task_struct *task;
	int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
	atomic_t total_allocated;
	atomic_t total_handles;
};

/**
+42 −16
Original line number Diff line number Diff line
@@ -390,21 +390,36 @@ 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];
		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);
				(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);
				(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];
		if (use_seq) {
			seq_printf(s,
				"%d order %u highmem pages in cached pool = %lu total\n",
				pool->high_count, pool->order,
@@ -412,8 +427,19 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
			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);
				(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;
}
+14 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/dma-contiguous.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/show_mem_notifier.h>
#include <asm/cacheflush.h>
#include "../ion_priv.h"
#include "ion_cp_common.h"
@@ -107,6 +108,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)
{
	/*
@@ -1052,6 +1064,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:
+2 −0
Original line number Diff line number Diff line
@@ -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 */