aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/oom_kill.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 21dd99eac..1a15cc0e1 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -44,6 +44,8 @@ int sysctl_oom_kill_allocating_task;
int sysctl_oom_dump_tasks = 1;
static DEFINE_SPINLOCK(zone_scan_lock);
+static unsigned long last_victim;
+
#ifdef CONFIG_NUMA
/**
* has_intersects_mems_allowed() - check task eligiblity for kill
@@ -264,14 +266,32 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task,
return OOM_SCAN_CONTINUE;
/*
- * This task already has access to memory reserves and is being killed.
- * Don't allow any other task to have access to the reserves.
+ * We found a task that we already tried to kill, but it hasn't
+ * finished dying yet. Generally we want to avoid choosing another
+ * victim until it finishes. If we choose lots of victims then we'll
+ * use up our memory reserves and none of the tasks will be able to
+ * exit.
+ *
+ * ...but we can't wait forever. If a task persistently refuses to
+ * die then it might be waiting on a resource (mutex or whatever) that
+ * won't be released until _some other_ task runs. ...and maybe that
+ * other is blocked waiting on memory (deadlock!). If it's been
+ * "long enough" then we'll just skip over existing victims and pick
+ * someone new to kill.
*/
if (test_tsk_thread_flag(task, TIF_MEMDIE)) {
if (unlikely(frozen(task)))
__thaw_task(task);
- if (!force_kill)
- return OOM_SCAN_ABORT;
+ if (!force_kill) {
+ if (time_after(jiffies,
+ last_victim + msecs_to_jiffies(100))) {
+ pr_warn("Task %s:%d refused to die\n",
+ task->comm, task->pid);
+ return OOM_SCAN_CONTINUE;
+ } else {
+ return OOM_SCAN_ABORT;
+ }
+ }
}
if (!task->mm)
return OOM_SCAN_CONTINUE;
@@ -435,6 +455,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
*/
if (p->flags & PF_EXITING) {
set_tsk_thread_flag(p, TIF_MEMDIE);
+ last_victim = jiffies;
put_task_struct(p);
return;
}
@@ -538,6 +559,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
rcu_read_unlock();
set_tsk_thread_flag(victim, TIF_MEMDIE);
+ last_victim = jiffies;
do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);
put_task_struct(victim);
}
@@ -670,6 +692,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
*/
if (fatal_signal_pending(current) || current->flags & PF_EXITING) {
set_thread_flag(TIF_MEMDIE);
+ last_victim = jiffies;
return;
}