|
@@ -412,6 +412,25 @@ bool oom_killer_disabled __read_mostly;
|
|
|
|
|
|
#define K(x) ((x) << (PAGE_SHIFT-10))
|
|
#define K(x) ((x) << (PAGE_SHIFT-10))
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * task->mm can be NULL if the task is the exited group leader. So to
|
|
|
|
+ * determine whether the task is using a particular mm, we examine all the
|
|
|
|
+ * task's threads: if one of those is using this mm then this task was also
|
|
|
|
+ * using it.
|
|
|
|
+ */
|
|
|
|
+static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *t;
|
|
|
|
+
|
|
|
|
+ for_each_thread(p, t) {
|
|
|
|
+ struct mm_struct *t_mm = READ_ONCE(t->mm);
|
|
|
|
+ if (t_mm)
|
|
|
|
+ return t_mm == mm;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
#ifdef CONFIG_MMU
|
|
#ifdef CONFIG_MMU
|
|
/*
|
|
/*
|
|
* OOM Reaper kernel thread which tries to reap the memory used by the OOM
|
|
* OOM Reaper kernel thread which tries to reap the memory used by the OOM
|
|
@@ -563,6 +582,53 @@ static void wake_oom_reaper(struct task_struct *tsk)
|
|
wake_up(&oom_reaper_wait);
|
|
wake_up(&oom_reaper_wait);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Check if we can reap the given task. This has to be called with stable
|
|
|
|
+ * tsk->mm
|
|
|
|
+ */
|
|
|
|
+void try_oom_reaper(struct task_struct *tsk)
|
|
|
|
+{
|
|
|
|
+ struct mm_struct *mm = tsk->mm;
|
|
|
|
+ struct task_struct *p;
|
|
|
|
+
|
|
|
|
+ if (!mm)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * There might be other threads/processes which are either not
|
|
|
|
+ * dying or even not killable.
|
|
|
|
+ */
|
|
|
|
+ if (atomic_read(&mm->mm_users) > 1) {
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+ for_each_process(p) {
|
|
|
|
+ bool exiting;
|
|
|
|
+
|
|
|
|
+ if (!process_shares_mm(p, mm))
|
|
|
|
+ continue;
|
|
|
|
+ if (same_thread_group(p, tsk))
|
|
|
|
+ continue;
|
|
|
|
+ if (fatal_signal_pending(p))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the task is exiting make sure the whole thread group
|
|
|
|
+ * is exiting and cannot acces mm anymore.
|
|
|
|
+ */
|
|
|
|
+ spin_lock_irq(&p->sighand->siglock);
|
|
|
|
+ exiting = signal_group_exit(p->signal);
|
|
|
|
+ spin_unlock_irq(&p->sighand->siglock);
|
|
|
|
+ if (exiting)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /* Give up */
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wake_oom_reaper(tsk);
|
|
|
|
+}
|
|
|
|
+
|
|
static int __init oom_init(void)
|
|
static int __init oom_init(void)
|
|
{
|
|
{
|
|
oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
|
|
oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
|
|
@@ -652,24 +718,6 @@ void oom_killer_enable(void)
|
|
oom_killer_disabled = false;
|
|
oom_killer_disabled = false;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * task->mm can be NULL if the task is the exited group leader. So to
|
|
|
|
- * determine whether the task is using a particular mm, we examine all the
|
|
|
|
- * task's threads: if one of those is using this mm then this task was also
|
|
|
|
- * using it.
|
|
|
|
- */
|
|
|
|
-static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
|
|
|
|
-{
|
|
|
|
- struct task_struct *t;
|
|
|
|
-
|
|
|
|
- for_each_thread(p, t) {
|
|
|
|
- struct mm_struct *t_mm = READ_ONCE(t->mm);
|
|
|
|
- if (t_mm)
|
|
|
|
- return t_mm == mm;
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Must be called while holding a reference to p, which will be released upon
|
|
* Must be called while holding a reference to p, which will be released upon
|
|
* returning.
|
|
* returning.
|
|
@@ -694,6 +742,7 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
|
|
task_lock(p);
|
|
task_lock(p);
|
|
if (p->mm && task_will_free_mem(p)) {
|
|
if (p->mm && task_will_free_mem(p)) {
|
|
mark_oom_victim(p);
|
|
mark_oom_victim(p);
|
|
|
|
+ try_oom_reaper(p);
|
|
task_unlock(p);
|
|
task_unlock(p);
|
|
put_task_struct(p);
|
|
put_task_struct(p);
|
|
return;
|
|
return;
|
|
@@ -873,6 +922,7 @@ bool out_of_memory(struct oom_control *oc)
|
|
if (current->mm &&
|
|
if (current->mm &&
|
|
(fatal_signal_pending(current) || task_will_free_mem(current))) {
|
|
(fatal_signal_pending(current) || task_will_free_mem(current))) {
|
|
mark_oom_victim(current);
|
|
mark_oom_victim(current);
|
|
|
|
+ try_oom_reaper(current);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|