mm: oom_kill: Support further prioritization of OOM kills

When the OOM killer selects a task to kill it considers all tasks
with an oom_score_adj value > OOM_SCORE_ADJ_MIN. This doesn't work
well when the OS has 'high priority' tasks which should only be
considered for killing after all other 'lower priority' tasks
have first been killed.

Add support for two new configs, PRIORITIZE_OOM_TASKS and
OOM_TASK_PRIORITY_ADJ_LIMIT, which allows the system to be configured
so that the OOM killer will first try to kill tasks which have an
oom_score_adj greater than a certain value.

Change-Id: Ic613138ae147427fd69b447ca5b674619ca625b2
Signed-off-by: Liam Mark <lmark@codeaurora.org>
This commit is contained in:
Liam Mark 2020-03-03 20:32:17 -08:00
commit 0c1d7417aa
3 changed files with 81 additions and 10 deletions

View file

@ -49,6 +49,9 @@ struct oom_control {
unsigned long totalpages;
struct task_struct *chosen;
unsigned long chosen_points;
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
short min_kill_adj;
#endif
/* Used to print the constraint info. */
enum oom_constraint constraint;

View file

@ -805,4 +805,31 @@ config ARCH_HAS_PTE_SPECIAL
config ARCH_HAS_HUGEPD
bool
config PRIORITIZE_OOM_TASKS
bool "Attempt to further prioritize OOM killer kills"
depends on QGKI
help
When the OOM killer selects a task to kill it considers all tasks
with a oom_score_adj value > OOM_SCORE_ADJ_MIN. This doesn't work
well when the OS has 'high priority' tasks which should only be
considered for killing after all other 'lower priority' tasks
have first been killed.
Enable this option to impose a limit on the minimum task
oom_score_adj which should first be considered for killing
before allowing the OOM killer to select tasks without
limitation.
If unsure, say N.
config OOM_TASK_PRIORITY_ADJ_LIMIT
int "Min oom_score_adj when priotizing OOM killer kills"
depends on PRIORITIZE_OOM_TASKS
range -1000 1000
default 0
help
With this parameter you can limit the OOM killer to first kill
tasks with an oom_score_adj value above a certain threshold
before considering tasks with a lower oom_score_adj value.
endmenu

View file

@ -317,6 +317,10 @@ static int oom_evaluate_task(struct task_struct *task, void *arg)
{
struct oom_control *oc = arg;
unsigned long points;
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
struct task_struct *p;
short adj;
#endif
if (oom_unkillable_task(task))
goto next;
@ -337,6 +341,18 @@ static int oom_evaluate_task(struct task_struct *task, void *arg)
goto abort;
}
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
p = find_lock_task_mm(task);
if (!p)
goto next;
adj = p->signal->oom_score_adj;
task_unlock(p);
if (adj < oc->min_kill_adj)
goto next;
#endif
/*
* If task is allocating a lot of memory and has been marked to be
* killed first if it triggers an oom, then select it.
@ -994,7 +1010,11 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
}
task_unlock(victim);
if (__ratelimit(&oom_rs))
if (__ratelimit(&oom_rs)
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
&& oc->min_kill_adj < CONFIG_OOM_TASK_PRIORITY_ADJ_LIMIT
#endif
)
dump_header(oc, victim);
/*
@ -1070,13 +1090,9 @@ bool out_of_memory(struct oom_control *oc)
if (oom_killer_disabled)
return false;
if (try_online_one_block(numa_node_id())) {
/* Got some memory back */
WARN(1, "OOM killer had to online a memory block\n");
return true;
}
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
oc->min_kill_adj = OOM_SCORE_ADJ_MIN;
#endif
if (!is_memcg_oom(oc)) {
blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
if (freed > 0)
@ -1112,19 +1128,44 @@ bool out_of_memory(struct oom_control *oc)
oc->constraint = constrained_alloc(oc);
if (oc->constraint != CONSTRAINT_MEMORY_POLICY)
oc->nodemask = NULL;
check_panic_on_oom(oc);
if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task &&
current->mm && !oom_unkillable_task(current) &&
oom_cpuset_eligible(current, oc) &&
current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
check_panic_on_oom(oc);
get_task_struct(current);
oc->chosen = current;
oom_kill_process(oc, "Out of memory (oom_kill_allocating_task)");
return true;
}
select_bad_process(oc);
#ifdef CONFIG_PRIORITIZE_OOM_TASKS
if (oc->min_kill_adj < CONFIG_OOM_TASK_PRIORITY_ADJ_LIMIT) {
short prev_min_kill_adj = oc->min_kill_adj;
oc->min_kill_adj = CONFIG_OOM_TASK_PRIORITY_ADJ_LIMIT;
select_bad_process(oc);
if (!oc->chosen) {
pr_warn_ratelimited("Could not find task with adj >= %d\n",
CONFIG_OOM_TASK_PRIORITY_ADJ_LIMIT);
oc->min_kill_adj = prev_min_kill_adj;
oc->chosen_points = 0;
}
}
#endif
if (!oc->chosen) {
if (try_online_one_block(numa_node_id())) {
/* Got some memory back */
WARN(1, "OOM killer had to online a memory block\n");
return true;
}
check_panic_on_oom(oc);
select_bad_process(oc);
}
/* Found nothing?!?! */
if (!oc->chosen) {
dump_header(oc, NULL);