Merge "lowmemorykiller:  use oom reaper to free pages of task killed by lmk "
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 616375a..8d67f76 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -48,6 +48,7 @@
 #include <linux/fs.h>
 #include <linux/cpuset.h>
 #include <linux/vmpressure.h>
+#include <linux/freezer.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/almk.h>
@@ -116,6 +117,10 @@
 static int vmpressure_file_min;
 module_param_named(vmpressure_file_min, vmpressure_file_min, int, 0644);
 
+/* User knob to enable/disable oom reaping feature */
+static int oom_reaper;
+module_param_named(oom_reaper, oom_reaper, int, 0644);
+
 enum {
 	VMPRESSURE_NO_ADJUST = 0,
 	VMPRESSURE_ADJUST_ENCROACH,
@@ -406,6 +411,14 @@
 	}
 }
 
+static void mark_lmk_victim(struct task_struct *tsk)
+{
+	struct mm_struct *mm = tsk->mm;
+
+	if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm))
+		atomic_inc(&tsk->signal->oom_mm->mm_count);
+}
+
 static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
 {
 	struct task_struct *tsk;
@@ -524,7 +537,11 @@
 		send_sig(SIGKILL, selected, 0);
 		if (selected->mm)
 			task_set_lmk_waiting(selected);
+		if (oom_reaper)
+			mark_lmk_victim(selected);
 		task_unlock(selected);
+		if (oom_reaper)
+			wake_oom_reaper(selected);
 		trace_lowmemory_kill(selected, cache_size, cache_limit, free);
 		lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
 			"to free %ldkB on behalf of '%s' (%d) because\n"
diff --git a/include/linux/oom.h b/include/linux/oom.h
index b986840..5b5d4c7 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -82,6 +82,8 @@
 extern void dump_tasks(struct mem_cgroup *memcg,
 		const nodemask_t *nodemask);
 
+extern void wake_oom_reaper(struct task_struct *tsk);
+
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
 extern int sysctl_oom_kill_allocating_task;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 3a22b14..af783a6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -608,18 +608,23 @@
 	return 0;
 }
 
-static void wake_oom_reaper(struct task_struct *tsk)
+void wake_oom_reaper(struct task_struct *tsk)
 {
 	if (!oom_reaper_th)
 		return;
 
+	/* move the lock here to avoid scenario of queuing
+	 * the same task by both OOM killer and LMK.
+	 */
+	spin_lock(&oom_reaper_lock);
 	/* tsk is already queued? */
-	if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+	if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+		spin_unlock(&oom_reaper_lock);
 		return;
+	}
 
 	get_task_struct(tsk);
 
-	spin_lock(&oom_reaper_lock);
 	tsk->oom_reaper_list = oom_reaper_list;
 	oom_reaper_list = tsk;
 	spin_unlock(&oom_reaper_lock);