From 91ce4829f646a6e1782248a4accab6e697a025f1 Mon Sep 17 00:00:00 2001 From: Chris Goldsworthy Date: Tue, 5 Jan 2021 14:57:00 -0800 Subject: [PATCH] ANDROID: mm, oom: Avoid killing tasks with negative ADJ scores Only kill a task with a negative ADJ score if there are no tasks with non-negative ADJ scores. Otherwise, kill the task with the most badness points whose ADJ score is also positive, if such a suitable task exists. Bug: 173837271 Signed-off-by: Chris Goldsworthy Change-Id: I70fe48a3eeb853085bb1acfb422f88cd36d1f14d --- include/linux/oom.h | 2 ++ mm/oom_kill.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/linux/oom.h b/include/linux/oom.h index b52ce6cfd687..106c1142b7bd 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -49,6 +49,8 @@ struct oom_control { unsigned long totalpages; struct task_struct *chosen; long chosen_points; + struct task_struct *chosen_non_negative_adj; + long chosen_non_negative_adj_points; /* Used to print the constraint info. */ enum oom_constraint constraint; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 32e25247f846..e8f2ba403e97 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -339,7 +339,24 @@ static int oom_evaluate_task(struct task_struct *task, void *arg) } points = oom_badness(task, oc->totalpages); - if (points == LONG_MIN || points < oc->chosen_points) + + if (points == LONG_MIN) + goto next; + + /* + * Check to see if this is the worst task with a non-negative + * ADJ score seen so far + */ + if (task->signal->oom_score_adj >= 0 && + points > oc->chosen_non_negative_adj_points) { + if (oc->chosen_non_negative_adj) + put_task_struct(oc->chosen_non_negative_adj); + get_task_struct(task); + oc->chosen_non_negative_adj = task; + oc->chosen_non_negative_adj_points = points; + } + + if (points < oc->chosen_points) goto next; select: @@ -351,6 +368,8 @@ static int oom_evaluate_task(struct task_struct *task, void *arg) next: return 0; abort: + if (oc->chosen_non_negative_adj) + put_task_struct(oc->chosen_non_negative_adj); if (oc->chosen) put_task_struct(oc->chosen); oc->chosen = (void *)-1UL; @@ -364,6 +383,8 @@ static int oom_evaluate_task(struct task_struct *task, void *arg) static void select_bad_process(struct oom_control *oc) { oc->chosen_points = LONG_MIN; + oc->chosen_non_negative_adj_points = LONG_MIN; + oc->chosen_non_negative_adj = NULL; if (is_memcg_oom(oc)) mem_cgroup_scan_tasks(oc->memcg, oom_evaluate_task, oc); @@ -376,6 +397,20 @@ static void select_bad_process(struct oom_control *oc) break; rcu_read_unlock(); } + + if (oc->chosen_non_negative_adj) { + /* + * If oc->chosen has a negative ADJ, and we found a task with + * a postive ADJ to kill, kill the task with the positive ADJ + * instead. + */ + if (oc->chosen && oc->chosen->signal->oom_score_adj < 0) { + put_task_struct(oc->chosen); + oc->chosen = oc->chosen_non_negative_adj; + oc->chosen_points = oc->chosen_non_negative_adj_points; + } else + put_task_struct(oc->chosen_non_negative_adj); + } } static int dump_task(struct task_struct *p, void *arg)