diff mbox

[v3,2/2] gpu: ion: oom killer

Message ID 1346827474-19709-3-git-send-email-zhangfei.gao@marvell.com
State Rejected
Headers show

Commit Message

Zhangfei Gao Sept. 5, 2012, 6:44 a.m. UTC
ion_shrink is called when ION_CARVEOUT_ALLOCATE_FAIL

How to test:
mount -t debugfs none /mnt
cat /mnt/ion/carveout_heap
echo adj > /mnt/ion/carveout_heap
send_sig SIGKILL to the task with higher adj and using ion buffer
Also kill all others tasks refered the buffers, in case using empty buffer

Example:

cat /mnt/ion/carveout_heap
client              pid             size    oom_score_adj
ion_test              191             4096                0
ion_test              192             4096                0
ion_test              193             4096                0

echo -1 > /mnt/ion/carveout_heap
[ 1333.689318] SIGKILL pid: 191
[ 1333.692192] SIGKILL pid: 192
[ 1333.695436] SIGKILL pid: 193
[ 1333.698312] SIGKILL pid: 193 size: 4096 adj: 0
[1]+  Killed                     ./ion_test 2

cat /mnt/ion/carveout_heap
client              pid             size    oom_score_adj

Signed-off-by: Zhangfei Gao <zhangfei.gao@marvell.com>
---
 drivers/gpu/ion/ion.c |  117 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 114 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 96f9cd7..383f588 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -32,6 +32,8 @@ 
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <linux/dma-buf.h>
+#include <linux/oom.h>
+#include <linux/delay.h>
 
 #include "ion_priv.h"
 
@@ -367,6 +369,8 @@  static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
 	rb_insert_color(&handle->node, &client->handles);
 }
 
+static int ion_shrink(struct ion_heap *heap, int kill_adj);
+
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 			     size_t align, unsigned int heap_mask,
 			     unsigned int flags)
@@ -375,6 +379,7 @@  struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 	struct ion_handle *handle;
 	struct ion_device *dev = client->dev;
 	struct ion_buffer *buffer = NULL;
+	struct ion_heap *heap_found = NULL;
 
 	pr_debug("%s: len %d align %d heap_mask %u flags %x\n", __func__, len,
 		 align, heap_mask, flags);
@@ -389,6 +394,7 @@  struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 
 	len = PAGE_ALIGN(len);
 
+retry:
 	mutex_lock(&dev->lock);
 	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
 		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
@@ -398,12 +404,18 @@  struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 		/* if the caller didn't specify this heap type */
 		if (!((1 << heap->id) & heap_mask))
 			continue;
+		heap_found = heap;
 		buffer = ion_buffer_create(heap, dev, len, align, flags);
 		if (!IS_ERR_OR_NULL(buffer))
 			break;
 	}
 	mutex_unlock(&dev->lock);
 
+	if ((buffer == ERR_PTR(-ENOMEM) && heap_found)) {
+		if (!ion_shrink(heap_found, 0))
+			goto retry;
+	}
+
 	if (buffer == NULL)
 		return ERR_PTR(-ENODEV);
 
@@ -1178,7 +1190,8 @@  static int ion_debug_heap_show(struct seq_file *s, void *unused)
 	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, "%16.s %16.s %16.s %16.s\n",
+		"client", "pid", "size", "oom_score_adj");
 	seq_printf(s, "----------------------------------------------------\n");
 
 	for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
@@ -1191,8 +1204,9 @@  static int ion_debug_heap_show(struct seq_file *s, void *unused)
 			char task_comm[TASK_COMM_LEN];
 
 			get_task_comm(task_comm, client->task);
-			seq_printf(s, "%16.s %16u %16u\n", task_comm,
-				   client->pid, size);
+			seq_printf(s, "%16.s %16u %16u %16d\n", task_comm,
+				   client->pid, size,
+				   client->task->signal->oom_score_adj);
 		} else {
 			seq_printf(s, "%16.s %16u %16u\n", client->name,
 				   client->pid, size);
@@ -1227,13 +1241,110 @@  static int ion_debug_heap_open(struct inode *inode, struct file *file)
 	return single_open(file, ion_debug_heap_show, inode->i_private);
 }
 
+static ssize_t
+ion_debug_heap_write(struct file *file, const char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	struct ion_heap *heap =
+		((struct seq_file *)file->private_data)->private;
+	char buf[16];
+	long kill_adj, ret;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	ret = kstrtol(buf, 10, &kill_adj);
+	if (ret)
+		return ret;
+
+	ion_shrink(heap, kill_adj);
+
+	return count;
+}
 static const struct file_operations debug_heap_fops = {
 	.open = ion_debug_heap_open,
+	.write = ion_debug_heap_write,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 };
 
+/*
+ * ion_shrink
+ * kill all tasks referd the buffer by selected task
+ */
+static int ion_shrink(struct ion_heap *heap, int kill_adj)
+{
+	struct rb_node *n;
+	struct ion_client *client = NULL;
+	struct ion_device *dev = heap->dev;
+	struct task_struct *selected = NULL;
+	int selected_size = 0;
+	int selected_oom_score_adj = 0;
+
+	for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
+		size_t size;
+		struct task_struct *p;
+
+		client = rb_entry(n, struct ion_client, node);
+		if (!client->task)
+			continue;
+
+		p = client->task;
+
+		if ((p->signal->oom_score_adj <= kill_adj) ||
+			(p->signal->oom_score_adj < selected_oom_score_adj))
+			continue;
+
+		size = ion_debug_heap_total(client, heap->id);
+		if (!size)
+			continue;
+		if (size < selected_size)
+			continue;
+
+		selected = p;
+		selected_size = size;
+		selected_oom_score_adj = p->signal->oom_score_adj;
+	}
+
+	if (selected) {
+		/* kill all proeces refer buffer shared with this client */
+		mutex_lock(&client->lock);
+		for (n = rb_first(&client->handles); n; n = rb_next(n)) {
+			struct rb_node *r;
+			struct ion_client *c;
+			struct ion_handle *handle = rb_entry(n,
+					struct ion_handle,
+					node);
+
+			for (r = rb_first(&dev->clients); r; r = rb_next(r)) {
+				struct ion_handle *h;
+
+				c = rb_entry(r, struct ion_client, node);
+				h = ion_handle_lookup(c, handle->buffer);
+				if (!IS_ERR_OR_NULL(h)) {
+					send_sig(SIGKILL, c->task, 0);
+					pr_info("SIGKILL pid: %u\n",
+							c->task->pid);
+				}
+
+			}
+		}
+		mutex_unlock(&client->lock);
+
+		send_sig(SIGKILL, selected, 0);
+		set_tsk_thread_flag(selected, TIF_MEMDIE);
+		pr_info("SIGKILL pid: %u size: %u adj: %u\n",
+				selected->pid, selected_size,
+				selected_oom_score_adj);
+		msleep(20);
+		return 0;
+	}
+	return -EAGAIN;
+}
+
 void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
 {
 	struct rb_node **p = &dev->heaps.rb_node;