public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: John Stultz <john.stultz@linaro.org>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>,
	Android Kernel Team <kernel-team@android.com>,
	Sumit Semwal <sumit.semwal@linaro.org>,
	Jesse Barker <jesse.barker@arm.com>,
	Colin Cross <ccross@android.com>,
	Rebecca Schultz Zavin <rebecca@android.com>,
	John Stultz <john.stultz@linaro.org>
Subject: [PATCH 065/115] gpu: ion: Also shrink memory cached in the deferred free list
Date: Fri, 13 Dec 2013 14:24:39 -0800	[thread overview]
Message-ID: <1386973529-4884-66-git-send-email-john.stultz@linaro.org> (raw)
In-Reply-To: <1386973529-4884-1-git-send-email-john.stultz@linaro.org>

From: Rebecca Schultz Zavin <rebecca@android.com>

When the system is low on memory, we want to shrink any cached
system memory ion is holding.  Previously we were shrinking memory
in the page pools, but not in the deferred free list.  This patch
makes it possible to shrink both.  It also moves the shrinker
code into the heaps so they can correctly manage any caches they
might contain.

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>
---
 drivers/staging/android/ion/ion.c             | 115 +++++++++--------------
 drivers/staging/android/ion/ion_heap.c        | 107 ++++++++++++++++++++++
 drivers/staging/android/ion/ion_page_pool.c   | 126 +++++---------------------
 drivers/staging/android/ion/ion_priv.h        |  57 +++++++++++-
 drivers/staging/android/ion/ion_system_heap.c |  49 ++++++++++
 5 files changed, 278 insertions(+), 176 deletions(-)

diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index b2dcee5..ddf8fde 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -28,8 +28,6 @@
 #include <linux/mm.h>
 #include <linux/mm_types.h>
 #include <linux/rbtree.h>
-#include <linux/rtmutex.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -143,7 +141,6 @@ static void ion_buffer_add(struct ion_device *dev,
 
 static int ion_buffer_alloc_dirty(struct ion_buffer *buffer);
 
-static bool ion_heap_drain_freelist(struct ion_heap *heap);
 /* this function should only be called while dev->lock is held */
 static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 				     struct ion_device *dev,
@@ -170,7 +167,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 		if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE))
 			goto err2;
 
-		ion_heap_drain_freelist(heap);
+		ion_heap_freelist_drain(heap, 0);
 		ret = heap->ops->allocate(heap, buffer, len, align,
 					  flags);
 		if (ret)
@@ -230,7 +227,7 @@ err2:
 	return ERR_PTR(ret);
 }
 
-static void _ion_buffer_destroy(struct ion_buffer *buffer)
+void ion_buffer_destroy(struct ion_buffer *buffer)
 {
 	if (WARN_ON(buffer->kmap_cnt > 0))
 		buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
@@ -241,7 +238,7 @@ static void _ion_buffer_destroy(struct ion_buffer *buffer)
 	kfree(buffer);
 }
 
-static void ion_buffer_destroy(struct kref *kref)
+static void _ion_buffer_destroy(struct kref *kref)
 {
 	struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
 	struct ion_heap *heap = buffer->heap;
@@ -251,14 +248,10 @@ static void ion_buffer_destroy(struct kref *kref)
 	rb_erase(&buffer->node, &dev->buffers);
 	mutex_unlock(&dev->buffer_lock);
 
-	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
-		rt_mutex_lock(&heap->lock);
-		list_add(&buffer->list, &heap->free_list);
-		rt_mutex_unlock(&heap->lock);
-		wake_up(&heap->waitqueue);
-		return;
-	}
-	_ion_buffer_destroy(buffer);
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+		ion_heap_freelist_add(heap, buffer);
+	else
+		ion_buffer_destroy(buffer);
 }
 
 static void ion_buffer_get(struct ion_buffer *buffer)
@@ -268,7 +261,7 @@ static void ion_buffer_get(struct ion_buffer *buffer)
 
 static int ion_buffer_put(struct ion_buffer *buffer)
 {
-	return kref_put(&buffer->ref, ion_buffer_destroy);
+	return kref_put(&buffer->ref, _ion_buffer_destroy);
 }
 
 static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
@@ -1298,80 +1291,53 @@ static const struct file_operations debug_heap_fops = {
 	.release = single_release,
 };
 
-static size_t ion_heap_free_list_is_empty(struct ion_heap *heap)
+#ifdef DEBUG_HEAP_SHRINKER
+static int debug_shrink_set(void *data, u64 val)
 {
-	bool is_empty;
+        struct ion_heap *heap = data;
+        struct shrink_control sc;
+        int objs;
 
-	rt_mutex_lock(&heap->lock);
-	is_empty = list_empty(&heap->free_list);
-	rt_mutex_unlock(&heap->lock);
+        sc.gfp_mask = -1;
+        sc.nr_to_scan = 0;
 
-	return is_empty;
-}
-
-static int ion_heap_deferred_free(void *data)
-{
-	struct ion_heap *heap = data;
+        if (!val)
+                return 0;
 
-	while (true) {
-		struct ion_buffer *buffer;
+        objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+        sc.nr_to_scan = objs;
 
-		wait_event_freezable(heap->waitqueue,
-				     !ion_heap_free_list_is_empty(heap));
-
-		rt_mutex_lock(&heap->lock);
-		if (list_empty(&heap->free_list)) {
-			rt_mutex_unlock(&heap->lock);
-			continue;
-		}
-		buffer = list_first_entry(&heap->free_list, struct ion_buffer,
-					  list);
-		list_del(&buffer->list);
-		rt_mutex_unlock(&heap->lock);
-		_ion_buffer_destroy(buffer);
-	}
-
-	return 0;
+        heap->shrinker.shrink(&heap->shrinker, &sc);
+        return 0;
 }
 
-static bool ion_heap_drain_freelist(struct ion_heap *heap)
+static int debug_shrink_get(void *data, u64 *val)
 {
-	struct ion_buffer *buffer, *tmp;
-
-	if (ion_heap_free_list_is_empty(heap))
-		return false;
-	rt_mutex_lock(&heap->lock);
-	list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
-		list_del(&buffer->list);
-		_ion_buffer_destroy(buffer);
-	}
-	BUG_ON(!list_empty(&heap->free_list));
-	rt_mutex_unlock(&heap->lock);
+        struct ion_heap *heap = data;
+        struct shrink_control sc;
+        int objs;
 
+        sc.gfp_mask = -1;
+        sc.nr_to_scan = 0;
 
-	return true;
+        objs = heap->shrinker.shrink(&heap->shrinker, &sc);
+        *val = objs;
+        return 0;
 }
 
+DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
+                        debug_shrink_set, "%llu\n");
+#endif
+
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
 {
-	struct sched_param param = { .sched_priority = 0 };
-
 	if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
 	    !heap->ops->unmap_dma)
 		pr_err("%s: can not add heap with invalid ops struct.\n",
 		       __func__);
 
-	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) {
-		INIT_LIST_HEAD(&heap->free_list);
-		rt_mutex_init(&heap->lock);
-		init_waitqueue_head(&heap->waitqueue);
-		heap->task = kthread_run(ion_heap_deferred_free, heap,
-					 "%s", heap->name);
-		sched_setscheduler(heap->task, SCHED_IDLE, &param);
-		if (IS_ERR(heap->task))
-			pr_err("%s: creating thread for deferred free failed\n",
-			       __func__);
-	}
+	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+		ion_heap_init_deferred_free(heap);
 
 	heap->dev = dev;
 	down_write(&dev->lock);
@@ -1381,6 +1347,15 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
 	plist_add(&heap->node, &dev->heaps);
 	debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
 			    &debug_heap_fops);
+#ifdef DEBUG_HEAP_SHRINKER
+	if (heap->shrinker.shrink) {
+		char debug_name[64];
+
+		snprintf(debug_name, 64, "%s_shrink", heap->name);
+		debugfs_create_file(debug_name, 0644, dev->debug_root, heap,
+				    &debug_shrink_fops);
+	}
+#endif
 	up_write(&dev->lock);
 }
 
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 11066a2..f541bff 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -15,7 +15,11 @@
  */
 
 #include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
 #include <linux/mm.h>
+#include <linux/rtmutex.h>
+#include <linux/sched.h>
 #include <linux/scatterlist.h>
 #include <linux/vmalloc.h>
 #include "ion.h"
@@ -130,6 +134,109 @@ end:
 	return ret;
 }
 
+void ion_heap_free_page(struct ion_buffer *buffer, struct page *page,
+		       unsigned int order)
+{
+	int i;
+
+	if (!ion_buffer_fault_user_mappings(buffer)) {
+		__free_pages(page, order);
+		return;
+	}
+	for (i = 0; i < (1 << order); i++)
+		__free_page(page + i);
+}
+
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer * buffer)
+{
+	rt_mutex_lock(&heap->lock);
+	list_add(&buffer->list, &heap->free_list);
+	heap->free_list_size += buffer->size;
+	rt_mutex_unlock(&heap->lock);
+	wake_up(&heap->waitqueue);
+}
+
+size_t ion_heap_freelist_size(struct ion_heap *heap)
+{
+	size_t size;
+
+	rt_mutex_lock(&heap->lock);
+	size = heap->free_list_size;
+	rt_mutex_unlock(&heap->lock);
+
+	return size;
+}
+
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
+{
+	struct ion_buffer *buffer, *tmp;
+	size_t total_drained = 0;
+
+	if (ion_heap_freelist_size(heap) == 0)
+		return 0;
+
+	rt_mutex_lock(&heap->lock);
+	if (size == 0)
+		size = heap->free_list_size;
+
+	list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) {
+		if (total_drained >= size)
+			break;
+		list_del(&buffer->list);
+		ion_buffer_destroy(buffer);
+		heap->free_list_size -= buffer->size;
+		total_drained += buffer->size;
+	}
+	rt_mutex_unlock(&heap->lock);
+
+	return total_drained;
+}
+
+int ion_heap_deferred_free(void *data)
+{
+	struct ion_heap *heap = data;
+
+	while (true) {
+		struct ion_buffer *buffer;
+
+		wait_event_freezable(heap->waitqueue,
+				     ion_heap_freelist_size(heap) > 0);
+
+		rt_mutex_lock(&heap->lock);
+		if (list_empty(&heap->free_list)) {
+			rt_mutex_unlock(&heap->lock);
+			continue;
+		}
+		buffer = list_first_entry(&heap->free_list, struct ion_buffer,
+					  list);
+		list_del(&buffer->list);
+		heap->free_list_size -= buffer->size;
+		rt_mutex_unlock(&heap->lock);
+		ion_buffer_destroy(buffer);
+	}
+
+	return 0;
+}
+
+int ion_heap_init_deferred_free(struct ion_heap *heap)
+{
+	struct sched_param param = { .sched_priority = 0 };
+
+	INIT_LIST_HEAD(&heap->free_list);
+	heap->free_list_size = 0;
+	rt_mutex_init(&heap->lock);
+	init_waitqueue_head(&heap->waitqueue);
+	heap->task = kthread_run(ion_heap_deferred_free, heap,
+				 "%s", heap->name);
+	sched_setscheduler(heap->task, SCHED_IDLE, &param);
+	if (IS_ERR(heap->task)) {
+		pr_err("%s: creating thread for deferred free failed\n",
+		       __func__);
+		return PTR_RET(heap->task);
+	}
+	return 0;
+}
+
 struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
 {
 	struct ion_heap *heap = NULL;
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index df6e29c..d624dee 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -21,14 +21,8 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/shrinker.h>
 #include "ion_priv.h"
 
-/* #define DEBUG_PAGE_POOL_SHRINKER */
-
-static struct plist_head pools = PLIST_HEAD_INIT(pools);
-static struct shrinker shrinker;
-
 struct ion_page_pool_item {
 	struct page *page;
 	struct list_head list;
@@ -126,109 +120,46 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page* page)
 		ion_page_pool_free_pages(pool, page);
 }
 
-#ifdef DEBUG_PAGE_POOL_SHRINKER
-static int debug_drop_pools_set(void *data, u64 val)
-{
-	struct shrink_control sc;
-	int objs;
-
-	sc.gfp_mask = -1;
-	sc.nr_to_scan = 0;
-
-	if (!val)
-		return 0;
-
-	objs = shrinker.shrink(&shrinker, &sc);
-	sc.nr_to_scan = objs;
-
-	shrinker.shrink(&shrinker, &sc);
-	return 0;
-}
-
-static int debug_drop_pools_get(void *data, u64 *val)
+static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
 {
-	struct shrink_control sc;
-	int objs;
-
-	sc.gfp_mask = -1;
-	sc.nr_to_scan = 0;
-
-	objs = shrinker.shrink(&shrinker, &sc);
-	*val = objs;
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_drop_pools_fops, debug_drop_pools_get,
-                        debug_drop_pools_set, "%llu\n");
-
-static int debug_grow_pools_set(void *data, u64 val)
-{
-	struct ion_page_pool *pool;
-	struct page *page;
-
-	plist_for_each_entry(pool, &pools, list) {
-		if (val != pool->list.prio)
-			continue;
-		page = ion_page_pool_alloc_pages(pool);
-		if (page)
-			ion_page_pool_add(pool, page);
-	}
-
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_grow_pools_fops, debug_drop_pools_get,
-			debug_grow_pools_set, "%llu\n");
-#endif
-
-static int ion_page_pool_total(bool high)
-{
-	struct ion_page_pool *pool;
 	int total = 0;
 
-	plist_for_each_entry(pool, &pools, list) {
-		total += high ? (pool->high_count + pool->low_count) *
-			(1 << pool->order) :
+	total += high ? (pool->high_count + pool->low_count) *
+		(1 << pool->order) :
 			pool->low_count * (1 << pool->order);
-	}
 	return total;
 }
 
-static int ion_page_pool_shrink(struct shrinker *shrinker,
-				 struct shrink_control *sc)
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+				int nr_to_scan)
 {
-	struct ion_page_pool *pool;
 	int nr_freed = 0;
 	int i;
 	bool high;
-	int nr_to_scan = sc->nr_to_scan;
 
-	high = sc->gfp_mask & __GFP_HIGHMEM;
+	high = gfp_mask & __GFP_HIGHMEM;
 
 	if (nr_to_scan == 0)
-		return ion_page_pool_total(high);
-
-	plist_for_each_entry(pool, &pools, list) {
-		for (i = 0; i < nr_to_scan; i++) {
-			struct page *page;
-
-			mutex_lock(&pool->mutex);
-			if (high && pool->high_count) {
-				page = ion_page_pool_remove(pool, true);
-			} else if (pool->low_count) {
-				page = ion_page_pool_remove(pool, false);
-			} else {
-				mutex_unlock(&pool->mutex);
-				break;
-			}
+		return ion_page_pool_total(pool, high);
+
+	for (i = 0; i < nr_to_scan; i++) {
+		struct page *page;
+
+		mutex_lock(&pool->mutex);
+		if (high && pool->high_count) {
+			page = ion_page_pool_remove(pool, true);
+		} else if (pool->low_count) {
+			page = ion_page_pool_remove(pool, false);
+		} else {
 			mutex_unlock(&pool->mutex);
-			ion_page_pool_free_pages(pool, page);
-			nr_freed += (1 << pool->order);
+			break;
 		}
-		nr_to_scan -= i;
+		mutex_unlock(&pool->mutex);
+		ion_page_pool_free_pages(pool, page);
+		nr_freed += (1 << pool->order);
 	}
 
-	return ion_page_pool_total(high);
+	return nr_freed;
 }
 
 struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
@@ -245,35 +176,22 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
 	pool->order = order;
 	mutex_init(&pool->mutex);
 	plist_node_init(&pool->list, order);
-	plist_add(&pool->list, &pools);
 
 	return pool;
 }
 
 void ion_page_pool_destroy(struct ion_page_pool *pool)
 {
-	plist_del(&pool->list, &pools);
 	kfree(pool);
 }
 
 static int __init ion_page_pool_init(void)
 {
-	shrinker.shrink = ion_page_pool_shrink;
-	shrinker.seeks = DEFAULT_SEEKS;
-	shrinker.batch = 0;
-	register_shrinker(&shrinker);
-#ifdef DEBUG_PAGE_POOL_SHRINKER
-	debugfs_create_file("ion_pools_shrink", 0644, NULL, NULL,
-			    &debug_drop_pools_fops);
-	debugfs_create_file("ion_pools_grow", 0644, NULL, NULL,
-			    &debug_grow_pools_fops);
-#endif
 	return 0;
 }
 
 static void __exit ion_page_pool_exit(void)
 {
-	unregister_shrinker(&shrinker);
 }
 
 module_init(ion_page_pool_init);
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index ab1a8d9..bdc1e34 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -82,6 +82,7 @@ struct ion_buffer {
 	char task_comm[TASK_COMM_LEN];
 	pid_t pid;
 };
+void ion_buffer_destroy(struct ion_buffer *buffer);
 
 /**
  * struct ion_heap_ops - ops to operate on a given heap
@@ -127,7 +128,12 @@ struct ion_heap_ops {
  *			allocating.  These are specified by platform data and
  *			MUST be unique
  * @name:		used for debugging
+ * @shrinker:		a shrinker for the heap, if the heap caches system
+ *			memory, it must define a shrinker to return it on low
+ *			memory conditions, this includes system memory cached
+ *			in the deferred free lists for heaps that support it
  * @free_list:		free list head if deferred free is used
+ * @free_list_size	size of the deferred free list in bytes
  * @lock:		protects the free list
  * @waitqueue:		queue to wait on from deferred free thread
  * @task:		task struct of deferred free thread
@@ -147,7 +153,9 @@ struct ion_heap {
 	unsigned long flags;
 	unsigned int id;
 	const char *name;
+	struct shrinker shrinker;
 	struct list_head free_list;
+	size_t free_list_size;
 	struct rt_mutex lock;
 	wait_queue_head_t waitqueue;
 	struct task_struct *task;
@@ -205,6 +213,43 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
 			struct vm_area_struct *);
 int ion_heap_buffer_zero(struct ion_buffer *buffer);
 
+/**
+ * ion_heap_init_deferred_free -- initialize deferred free functionality
+ * @heap:		the heap
+ *
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag this function will
+ * be called to setup deferred frees. Calls to free the buffer will
+ * return immediately and the actual free will occur some time later
+ */
+int ion_heap_init_deferred_free(struct ion_heap *heap);
+
+/**
+ * ion_heap_freelist_add - add a buffer to the deferred free list
+ * @heap:		the heap
+ * @buffer: 		the buffer
+ *
+ * Adds an item to the deferred freelist.
+ */
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
+
+/**
+ * ion_heap_freelist_drain - drain the deferred free list
+ * @heap:		the heap
+ * @size:		ammount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed.  The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ */
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
+
+/**
+ * ion_heap_freelist_size - returns the size of the freelist in bytes
+ * @heap:		the heap
+ */
+size_t ion_heap_freelist_size(struct ion_heap *heap);
+
 
 /**
  * functions for creating and destroying the built in ion heaps.
@@ -274,8 +319,6 @@ struct ion_page_pool {
 	struct list_head high_items;
 	struct list_head low_items;
 	struct mutex mutex;
-	void *(*alloc)(struct ion_page_pool *pool);
-	void (*free)(struct ion_page_pool *pool, struct page *page);
 	gfp_t gfp_mask;
 	unsigned int order;
 	struct plist_node list;
@@ -286,4 +329,14 @@ void ion_page_pool_destroy(struct ion_page_pool *);
 void *ion_page_pool_alloc(struct ion_page_pool *);
 void ion_page_pool_free(struct ion_page_pool *, struct page *);
 
+/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
+ * @pool:		the pool
+ * @gfp_mask:		the memory type to reclaim
+ * @nr_to_scan:		number of items to shrink in pages
+ *
+ * returns the number of items freed in pages
+ */
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+			  int nr_to_scan);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 6665797..fedbc0d 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -253,6 +253,50 @@ static struct ion_heap_ops system_heap_ops = {
 	.map_user = ion_heap_map_user,
 };
 
+static int ion_system_heap_shrink(struct shrinker *shrinker,
+				  struct shrink_control *sc) {
+
+	struct ion_heap *heap = container_of(shrinker, struct ion_heap,
+					     shrinker);
+	struct ion_system_heap *sys_heap = container_of(heap,
+							struct ion_system_heap,
+							heap);
+	int nr_total = 0;
+	int nr_freed = 0;
+	int i;
+
+	if (sc->nr_to_scan == 0)
+		goto end;
+
+	/* shrink the free list first, no point in zeroing the memory if
+	   we're just going to reclaim it */
+	nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) /
+		PAGE_SIZE;
+
+	if (nr_freed >= sc->nr_to_scan)
+		goto end;
+
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool = sys_heap->pools[i];
+
+		nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask,
+						 sc->nr_to_scan);
+		if (nr_freed >= sc->nr_to_scan)
+			break;
+	}
+
+end:
+	/* total number of items is whatever the page pools are holding
+	   plus whatever's in the freelist */
+	for (i = 0; i < num_orders; i++) {
+		struct ion_page_pool *pool = sys_heap->pools[i];
+		nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0);
+	}
+	nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE;
+	return nr_total;
+
+}
+
 static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
 				      void *unused)
 {
@@ -299,6 +343,11 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
 			goto err_create_pool;
 		heap->pools[i] = pool;
 	}
+
+	heap->heap.shrinker.shrink = ion_system_heap_shrink;
+	heap->heap.shrinker.seeks = DEFAULT_SEEKS;
+	heap->heap.shrinker.batch = 0;
+	register_shrinker(&heap->heap.shrinker);
 	heap->heap.debug_show = ion_system_heap_debug_show;
 	return &heap->heap;
 err_create_pool:
-- 
1.8.3.2


  parent reply	other threads:[~2013-12-13 22:27 UTC|newest]

Thread overview: 134+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-13 22:23 [PATCH 000/115] Android ION for drivers/staging John Stultz
2013-12-13 22:23 ` [PATCH 001/115] gpu: ion: Add ION Memory Manager John Stultz
2013-12-13 23:50   ` Greg KH
2013-12-13 23:54     ` John Stultz
2013-12-14  0:53       ` John Stultz
2013-12-14  1:18     ` John Stultz
2013-12-14 17:06       ` Greg KH
2013-12-14 19:43         ` John Stultz
2013-12-14 19:53           ` John Stultz
2013-12-14 20:06         ` [PATCH 1/2] ion: Don't allow building ION as a module John Stultz
2013-12-14 20:06           ` [PATCH 2/2] ion: Reenable the build John Stultz
2013-12-14 21:48           ` [PATCH 1/2] ion: Don't allow building ION as a module Greg KH
2013-12-14 22:19             ` John Stultz
2013-12-14 23:15               ` Colin Cross
2013-12-14 16:52   ` [PATCH 001/115] gpu: ion: Add ION Memory Manager Greg KH
2013-12-14 21:10     ` Colin Cross
2013-12-14 21:44       ` Greg KH
2013-12-14 22:21         ` Colin Cross
2013-12-14 23:14           ` Greg KH
2013-12-13 22:23 ` [PATCH 002/115] gpu: ion: ion_carveout_heap: fix for 3.4 John Stultz
2013-12-13 22:23 ` [PATCH 003/115] ion: Switch map/unmap dma api to sg_tables John Stultz
2013-12-13 22:23 ` [PATCH 004/115] ion: Add reserve function to ion John Stultz
2013-12-13 22:23 ` [PATCH 005/115] gpu: ion: several bugfixes and enhancements of ION John Stultz
2013-12-13 22:23 ` [PATCH 006/115] ion: Switch ion to use dma-buf John Stultz
2013-12-13 22:23 ` [PATCH 007/115] gpu: ion: Use alloc_pages instead of vmalloc from the system heap John Stultz
2013-12-13 22:23 ` [PATCH 008/115] gpu: ion: support begin/end and kmap/kunmap dma_buf ops John Stultz
2013-12-13 22:23 ` [PATCH 009/115] gpu: ion: Allocate the sg_table at creation time rather than dynamically John Stultz
2013-12-13 22:23 ` [PATCH 010/115] gpu: ion: Get an sg_table from an ion handle John Stultz
2013-12-13 22:23 ` [PATCH 011/115] gpu: ion: fill in buffer->{dev,size} before mapping new buffers John Stultz
2013-12-13 22:23 ` [PATCH 012/115] gpu: ion: Set the dma_address of the sg list at alloc time John Stultz
2013-12-13 22:23 ` [PATCH 013/115] gpu: ion: ion_system_heap: Change allocations to GFP_HIGHUSER John Stultz
2013-12-13 22:23 ` [PATCH 014/115] gpu: ion: Loop on the handle count when destroying John Stultz
2013-12-13 22:23 ` [PATCH 015/115] gpu: ion: Map only the vma size given John Stultz
2013-12-13 22:23 ` [PATCH 016/115] gpu: ion: Add cache maintenance to ion John Stultz
2013-12-13 22:23 ` [PATCH 017/115] gpu: ion: Modify the system heap to try to allocate large/huge pages John Stultz
2013-12-13 22:23 ` [PATCH 018/115] gpu: ion: Add explicit sync ioctl John Stultz
2013-12-13 22:23 ` [PATCH 019/115] gpu: ion: do not ask for compound pages in system heap John Stultz
2013-12-13 22:23 ` [PATCH 020/115] gpu: ion: Add missing argument to WARN call John Stultz
2013-12-13 22:23 ` [PATCH 021/115] gpu: ion: Add EXPORT_SYMBOL to functions John Stultz
2013-12-13 22:23 ` [PATCH 022/115] gpu: ion: IOCTL return success when error occurs John Stultz
2013-12-13 22:23 ` [PATCH 023/115] gpu: ion: Don't call ion_buffer_put on error path John Stultz
2013-12-13 22:23 ` [PATCH 024/115] gpu: ion: Only map as much of the vma as the user requested John Stultz
2013-12-13 22:23 ` [PATCH 025/115] gpu: ion: Switch to using kmalloc rather than kmap during allocation John Stultz
2013-12-13 22:24 ` [PATCH 026/115] gpu: ion: fix page offset in dma_buf_kmap() John Stultz
2013-12-13 22:24 ` [PATCH 027/115] gpu: ion: Fix race between ion_import and ion_free John Stultz
2013-12-13 22:24 ` [PATCH 028/115] gpu: ion: Fix bug in ion_free John Stultz
2013-12-13 22:24 ` [PATCH 029/115] gpu: ion: Add debug information for orphaned handles John Stultz
2013-12-13 22:24 ` [PATCH 030/115] gpu: ion: Fix memory leak of dirty bits John Stultz
2013-12-13 22:24 ` [PATCH 031/115] gpu: ion: Add support for cached mappings that don't fault John Stultz
2013-12-13 22:24 ` [PATCH 032/115] gpu: ion: optimize system heap for non fault buffers John Stultz
2013-12-13 22:24 ` [PATCH 033/115] gpu: ion: Stop trying to allocate from an order on first failure John Stultz
2013-12-13 22:24 ` [PATCH 034/115] gpu: ion: ion_system_heap: Fix bug preventing compilation John Stultz
2013-12-13 22:24 ` [PATCH 035/115] gpu: ion: use vmalloc to allocate page array to map kernel John Stultz
2013-12-13 22:24 ` [PATCH 036/115] gpu: ion: Add ion_page_pool John Stultz
2013-12-13 22:24 ` [PATCH 037/115] gpu: ion: Use the ion_page_pool from the system heap John Stultz
2013-12-13 22:24 ` [PATCH 038/115] gpu: ion: Modify gfp flags in ion_system_heap John Stultz
2013-12-13 22:24 ` [PATCH 039/115] gpu: ion: Fix several issues with page pool John Stultz
2013-12-13 22:24 ` [PATCH 040/115] gpu: ion: Fix lockdep issue in ion_page_pool John Stultz
2013-12-13 22:24 ` [PATCH 041/115] gpu: ion: Switch to using a single shrink function John Stultz
2013-12-13 22:24 ` [PATCH 042/115] gpu: ion: Refactor locking John Stultz
2013-12-13 22:24 ` [PATCH 043/115] gpu: ion: Clear GFP_WAIT flag on high order allocations John Stultz
2013-12-13 22:24 ` [PATCH 044/115] gpu: ion: Don't flush allocatoins that come from the page pools John Stultz
2013-12-13 22:24 ` [PATCH 045/115] gpu: ion: Fix bug in ion_system_heap map_user John Stultz
2013-12-13 22:24 ` [PATCH 046/115] gpu: ion: Fix bug in zeroing pages in system heap John Stultz
2013-12-13 22:24 ` [PATCH 047/115] gpu: ion: fix carveout ops John Stultz
2013-12-13 22:24 ` [PATCH 048/115] gpu: ion: fix compilation warning John Stultz
2013-12-13 22:24 ` [PATCH 049/115] gpu: ion: Modify reserve function for carveouts with no start address John Stultz
2013-12-13 22:24 ` [PATCH 050/115] gpu: ion: Fix bug where MAP ioctl was no longer supported John Stultz
2013-12-13 22:24 ` [PATCH 051/115] gpu: ion: Switch heap rbtree to a prio list John Stultz
2013-12-13 22:24 ` [PATCH 052/115] gpu: ion: Refactor common mapping functions out of system heap John Stultz
2013-12-13 22:24 ` [PATCH 053/115] gpu: ion: Add chunk heap John Stultz
2013-12-13 22:24 ` [PATCH 054/115] gpu: ion: Clarify variable names and comments around heap ids v types John Stultz
2013-12-13 22:24 ` [PATCH 055/115] gpu: ion: Export ion_client_create John Stultz
2013-12-13 22:24 ` [PATCH 056/115] gpu: ion: Remove heapmask from client John Stultz
2013-12-13 22:24 ` [PATCH 057/115] gpu: ion: Modify zeroing code so it only allocates address space once John Stultz
2013-12-13 22:24 ` [PATCH 058/115] gpu: ion: Refactor the code to zero buffers John Stultz
2013-12-13 22:24 ` [PATCH 059/115] gpu: ion: Only flush buffers in the chunk heap if they were used cached John Stultz
2013-12-13 22:24 ` [PATCH 060/115] gpu: ion: Add support for sharing buffers with dma buf kernel handles John Stultz
2013-12-13 22:24 ` [PATCH 061/115] gpu: ion: Make ion_free asynchronous John Stultz
2013-12-13 22:24 ` [PATCH 062/115] gpu: ion: fix kfree/list_del order John Stultz
2013-12-13 22:24 ` [PATCH 063/115] gpu: ion: ion_chunk_heap: Zero chunk heap memory at creation time John Stultz
2013-12-13 22:24 ` [PATCH 064/115] gpu: ion: Fix bug in ion shrinker John Stultz
2013-12-13 22:24 ` John Stultz [this message]
2013-12-13 22:24 ` [PATCH 066/115] gpu: ion: __dma_page_cpu_to_dev -> arm_dma_ops.sync_single_for_device hack John Stultz
2013-12-13 22:24 ` [PATCH 067/115] gpu: ion: Remove __GFP_NO_KSWAPD John Stultz
2013-12-13 22:24 ` [PATCH 068/115] ion: Add Kconfig dependency to ARM John Stultz
2013-12-13 22:24 ` [PATCH 069/115] gpu: ion: fix ion_platform_data definition John Stultz
2013-12-13 22:24 ` [PATCH 070/115] gpu: ion: add CMA heap John Stultz
2013-12-13 22:24 ` [PATCH 071/115] gpu: ion: Fix performance issue in faulting code John Stultz
2013-12-13 22:24 ` [PATCH 072/115] ion: chunk_heap: fix leak in allocated counter John Stultz
2013-12-13 22:24 ` [PATCH 073/115] ion: add free list size to heap debug files John Stultz
2013-12-13 22:24 ` [PATCH 074/115] ion: convert map_kernel to return ERR_PTR John Stultz
2013-12-13 22:24 ` [PATCH 075/115] ion: remove IS_ERR_OR_NULL John Stultz
2013-12-13 22:24 ` [PATCH 076/115] ion: replace userspace handle cookies with idr John Stultz
2013-12-13 22:24 ` [PATCH 077/115] ion: index client->handles rbtree by buffer John Stultz
2013-12-13 22:24 ` [PATCH 078/115] ion: don't use id 0 for handle cookie John Stultz
2013-12-13 22:24 ` [PATCH 079/115] ion: add new ion_user_handle_t type for the user-space token John Stultz
2013-12-13 22:24 ` [PATCH 080/115] ion: change ion_user_handle_t definition to int John Stultz
2013-12-13 22:24 ` [PATCH 081/115] ion: add compat_ioctl John Stultz
2013-12-13 22:24 ` [PATCH 082/115] gpu: ion: delete ion_system_mapper.c John Stultz
2013-12-13 22:24 ` [PATCH 083/115] ion: move userspace api into uapi/ion.h John Stultz
2013-12-13 22:24 ` [PATCH 084/115] ion: Fix compat support to use proper compat ioctl numbers John Stultz
2013-12-13 22:24 ` [PATCH 085/115] ion: hold reference to handle after ion_uhandle_get John Stultz
2013-12-13 22:25 ` [PATCH 086/115] ion: fix crash when alloc len is -1 John Stultz
2013-12-13 22:25 ` [PATCH 087/115] ion: fix dma APIs John Stultz
2013-12-13 22:25 ` [PATCH 088/115] ion: convert sg_dma_len(sg) to sg->length John Stultz
2013-12-13 22:25 ` [PATCH 089/115] ion: check invalid values in ion_system_heap John Stultz
2013-12-13 22:25 ` [PATCH 090/115] ion: add test device for unit tests to interact with dma_bufs John Stultz
2013-12-13 22:25 ` [PATCH 091/115] ion: update idr to avoid deprecated apis John Stultz
2013-12-13 22:25 ` [PATCH 092/115] ion: don't use __arm_ioremap to map pages John Stultz
2013-12-14  3:26 ` [PATCH 093/115] ion: don't use phys_to_page or __phys_to_pfn John Stultz
2013-12-14  3:26   ` [PATCH 094/115] ion: fix printk warnings John Stultz
2013-12-14  4:27     ` Joe Perches
2013-12-14  3:26   ` [PATCH 095/115] gpu: ion: remove unnecessary function from system heap John Stultz
2013-12-14  3:26   ` [PATCH 096/115] ion: clean up ioctls John Stultz
2013-12-14  3:26   ` [PATCH 097/115] gpu: ion: fix use-after-free in ion_heap_freelist_drain John Stultz
2013-12-14  3:26   ` [PATCH 098/115] ion: Fix two small issues in system_heap allocation John Stultz
2013-12-14  3:26   ` [PATCH 099/115] ion: drop dependency on ARM John Stultz
2013-12-14  3:26   ` [PATCH 100/115] ion: add alignment check to carveout heap John Stultz
2013-12-14  3:26   ` [PATCH 101/115] ion: optimize ion_heap_buffer_zero John Stultz
2013-12-14  3:26   ` [PATCH 102/115] ion: free low memory from page pools first John Stultz
2013-12-14  3:26   ` [PATCH 103/115] ion: check return value from remap_pfn_range John Stultz
2013-12-14  3:26   ` [PATCH 104/115] ion: use vm_insert_pfn for faulted pages John Stultz
2013-12-14  3:26   ` [PATCH 105/115] ion: remove ion_heap_alloc_pages John Stultz
2013-12-14  3:26   ` [PATCH 106/115] ion: allow cached mappings of chunk and system heap buffers John Stultz
2013-12-14  3:26   ` [PATCH 107/115] ion: use alloc_pages in system contig heap John Stultz
2013-12-14  3:26   ` [PATCH 108/115] ion: fix sparse warnings John Stultz
2013-12-14  3:26   ` [PATCH 109/115] ion: carveout heap: zero buffers on free, fix memory leak John Stultz
2013-12-14  3:26   ` [PATCH 110/115] ion: add helper to zero contiguous region of pages John Stultz
2013-12-14  3:26   ` [PATCH 111/115] ion: add alignment check to chunk heap John Stultz
2013-12-14  3:26   ` [PATCH 112/115] ion: fix bugs in cma heap John Stultz
2013-12-14  3:26   ` [PATCH 113/115] ion: Cleanup whitespace issues and other checkpatch problems John Stultz
2013-12-14  3:26   ` [PATCH 114/115] ion: Improve ION config description John Stultz
2013-12-14  3:26   ` [PATCH 115/115] ion: Update system heap shrinker to use the new count/scan interface John Stultz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1386973529-4884-66-git-send-email-john.stultz@linaro.org \
    --to=john.stultz@linaro.org \
    --cc=ccross@android.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jesse.barker@arm.com \
    --cc=kernel-team@android.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rebecca@android.com \
    --cc=sumit.semwal@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox