ANDROID: mm: oom_kill: reap memory of a task that receives SIGKILL

Free the pages parallely for a task that receives SIGKILL, from ULMK
process, using the oom_reaper. This freeing of pages will help to give
the pages to buddy system well advance.

Add the boot param, reap_mem_when_killed_by=, that configures the
process name, the kill signal to a process from which makes its memory
reaped by oom reaper.

As an example, when reap_mem_when_killed_by=lmkd, then all the processes
that receives the kill signal from lmkd is added to oom reaper.

Not initializing this param makes this feature disabled.

Change-Id: I21adb95de5e380a80d7eb0b87d9b5b553f52e28a
Bug: 171763461
Signed-off-by: Charan Teja Reddy <charante@codeaurora.org>
Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b885bbf..b8fa202 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4604,6 +4604,10 @@
 				(that will set all pages holding image data
 				during restoration read-only).
 
+	reap_mem_when_killed_by=
+			The name of a process, the kill signal from which to a process
+			make its memory reaped with oom reaper.
+
 	retain_initrd	[RAM] Keep initrd memory after extraction
 
 	rfkill.default_state=
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 2db9a14..b52ce6c 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -127,4 +127,7 @@ extern struct task_struct *find_lock_task_mm(struct task_struct *p);
 extern int sysctl_oom_dump_tasks;
 extern int sysctl_oom_kill_allocating_task;
 extern int sysctl_panic_on_oom;
+
+/* calls for LMK reaper */
+extern void add_to_oom_reaper(struct task_struct *p);
 #endif /* _INCLUDE_LINUX_OOM_H */
diff --git a/kernel/signal.c b/kernel/signal.c
index dd83edc..5a4d060 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -46,6 +46,7 @@
 #include <linux/livepatch.h>
 #include <linux/cgroup.h>
 #include <linux/audit.h>
+#include <linux/oom.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
@@ -64,6 +65,18 @@ static struct kmem_cache *sigqueue_cachep;
 
 int print_fatal_signals __read_mostly;
 
+static char reaper_comm[TASK_COMM_LEN];
+
+static __init int setup_mem_reap(char *str)
+{
+	if (!str)
+		return 0;
+	strlcpy(reaper_comm, str, TASK_COMM_LEN);
+
+	return 1;
+}
+__setup("reap_mem_when_killed_by=", setup_mem_reap);
+
 static void __user *sig_handler(struct task_struct *t, int sig)
 {
 	return t->sighand->action[sig - 1].sa.sa_handler;
@@ -1411,8 +1424,12 @@ int group_send_sig_info(int sig, struct kernel_siginfo *info,
 	ret = check_kill_permission(sig, info, p);
 	rcu_read_unlock();
 
-	if (!ret && sig)
+	if (!ret && sig) {
 		ret = do_send_sig_info(sig, info, p, type);
+		if (!ret && sig == SIGKILL &&
+			!strcmp(current->comm, reaper_comm))
+			add_to_oom_reaper(p);
+	}
 
 	return ret;
 }
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 8b84661..32e25247 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -686,6 +686,20 @@ static inline void wake_oom_reaper(struct task_struct *tsk)
 #endif /* CONFIG_MMU */
 
 /**
+ * tsk->mm has to be non NULL and caller has to guarantee it is stable (either
+ * under task_lock or operate on the current).
+ */
+static void __mark_oom_victim(struct task_struct *tsk)
+{
+	struct mm_struct *mm = tsk->mm;
+
+	if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
+		mmgrab(tsk->signal->oom_mm);
+		set_bit(MMF_OOM_VICTIM, &mm->flags);
+	}
+}
+
+/**
  * mark_oom_victim - mark the given task as OOM victim
  * @tsk: task to mark
  *
@@ -697,18 +711,13 @@ static inline void wake_oom_reaper(struct task_struct *tsk)
  */
 static void mark_oom_victim(struct task_struct *tsk)
 {
-	struct mm_struct *mm = tsk->mm;
-
 	WARN_ON(oom_killer_disabled);
 	/* OOM killer might race with memcg OOM */
 	if (test_and_set_tsk_thread_flag(tsk, TIF_MEMDIE))
 		return;
 
 	/* oom_mm is bound to the signal struct life time. */
-	if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) {
-		mmgrab(tsk->signal->oom_mm);
-		set_bit(MMF_OOM_VICTIM, &mm->flags);
-	}
+	__mark_oom_victim(tsk);
 
 	/*
 	 * Make sure that the task is woken up from uninterruptible sleep
@@ -1140,3 +1149,18 @@ void pagefault_out_of_memory(void)
 	out_of_memory(&oc);
 	mutex_unlock(&oom_lock);
 }
+
+void add_to_oom_reaper(struct task_struct *p)
+{
+	p = find_lock_task_mm(p);
+	if (!p)
+		return;
+
+	get_task_struct(p);
+	if (task_will_free_mem(p)) {
+		__mark_oom_victim(p);
+		wake_oom_reaper(p);
+	}
+	task_unlock(p);
+	put_task_struct(p);
+}