Skip to content

Commit 3ef22df

Browse files
Michal Hockotorvalds
authored andcommitted
oom, oom_reaper: try to reap tasks which skip regular OOM killer path
If either the current task is already killed or PF_EXITING or a selected task is PF_EXITING then the oom killer is suppressed and so is the oom reaper. This patch adds try_oom_reaper which checks the given task and queues it for the oom reaper if that is safe to be done meaning that the task doesn't share the mm with an alive process. This might help to release the memory pressure while the task tries to exit. [akpm@linux-foundation.org: fix nommu build] Signed-off-by: Michal Hocko <mhocko@suse.com> Cc: Raushaniya Maksudova <rmaksudova@parallels.com> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: David Rientjes <rientjes@google.com> Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Cc: Daniel Vetter <daniel.vetter@intel.com> Cc: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 3da88fb commit 3ef22df

File tree

3 files changed

+77
-18
lines changed

3 files changed

+77
-18
lines changed

include/linux/oom.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ static inline bool oom_task_origin(const struct task_struct *p)
7272

7373
extern void mark_oom_victim(struct task_struct *tsk);
7474

75+
#ifdef CONFIG_MMU
76+
extern void try_oom_reaper(struct task_struct *tsk);
77+
#else
78+
static inline void try_oom_reaper(struct task_struct *tsk)
79+
{
80+
}
81+
#endif
82+
7583
extern unsigned long oom_badness(struct task_struct *p,
7684
struct mem_cgroup *memcg, const nodemask_t *nodemask,
7785
unsigned long totalpages);

mm/memcontrol.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,7 @@ static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
12751275
*/
12761276
if (fatal_signal_pending(current) || task_will_free_mem(current)) {
12771277
mark_oom_victim(current);
1278+
try_oom_reaper(current);
12781279
goto unlock;
12791280
}
12801281

mm/oom_kill.c

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,25 @@ bool oom_killer_disabled __read_mostly;
412412

413413
#define K(x) ((x) << (PAGE_SHIFT-10))
414414

415+
/*
416+
* task->mm can be NULL if the task is the exited group leader. So to
417+
* determine whether the task is using a particular mm, we examine all the
418+
* task's threads: if one of those is using this mm then this task was also
419+
* using it.
420+
*/
421+
static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
422+
{
423+
struct task_struct *t;
424+
425+
for_each_thread(p, t) {
426+
struct mm_struct *t_mm = READ_ONCE(t->mm);
427+
if (t_mm)
428+
return t_mm == mm;
429+
}
430+
return false;
431+
}
432+
433+
415434
#ifdef CONFIG_MMU
416435
/*
417436
* 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)
563582
wake_up(&oom_reaper_wait);
564583
}
565584

585+
/* Check if we can reap the given task. This has to be called with stable
586+
* tsk->mm
587+
*/
588+
void try_oom_reaper(struct task_struct *tsk)
589+
{
590+
struct mm_struct *mm = tsk->mm;
591+
struct task_struct *p;
592+
593+
if (!mm)
594+
return;
595+
596+
/*
597+
* There might be other threads/processes which are either not
598+
* dying or even not killable.
599+
*/
600+
if (atomic_read(&mm->mm_users) > 1) {
601+
rcu_read_lock();
602+
for_each_process(p) {
603+
bool exiting;
604+
605+
if (!process_shares_mm(p, mm))
606+
continue;
607+
if (same_thread_group(p, tsk))
608+
continue;
609+
if (fatal_signal_pending(p))
610+
continue;
611+
612+
/*
613+
* If the task is exiting make sure the whole thread group
614+
* is exiting and cannot acces mm anymore.
615+
*/
616+
spin_lock_irq(&p->sighand->siglock);
617+
exiting = signal_group_exit(p->signal);
618+
spin_unlock_irq(&p->sighand->siglock);
619+
if (exiting)
620+
continue;
621+
622+
/* Give up */
623+
rcu_read_unlock();
624+
return;
625+
}
626+
rcu_read_unlock();
627+
}
628+
629+
wake_oom_reaper(tsk);
630+
}
631+
566632
static int __init oom_init(void)
567633
{
568634
oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper");
@@ -652,24 +718,6 @@ void oom_killer_enable(void)
652718
oom_killer_disabled = false;
653719
}
654720

655-
/*
656-
* task->mm can be NULL if the task is the exited group leader. So to
657-
* determine whether the task is using a particular mm, we examine all the
658-
* task's threads: if one of those is using this mm then this task was also
659-
* using it.
660-
*/
661-
static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
662-
{
663-
struct task_struct *t;
664-
665-
for_each_thread(p, t) {
666-
struct mm_struct *t_mm = READ_ONCE(t->mm);
667-
if (t_mm)
668-
return t_mm == mm;
669-
}
670-
return false;
671-
}
672-
673721
/*
674722
* Must be called while holding a reference to p, which will be released upon
675723
* returning.
@@ -694,6 +742,7 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
694742
task_lock(p);
695743
if (p->mm && task_will_free_mem(p)) {
696744
mark_oom_victim(p);
745+
try_oom_reaper(p);
697746
task_unlock(p);
698747
put_task_struct(p);
699748
return;
@@ -873,6 +922,7 @@ bool out_of_memory(struct oom_control *oc)
873922
if (current->mm &&
874923
(fatal_signal_pending(current) || task_will_free_mem(current))) {
875924
mark_oom_victim(current);
925+
try_oom_reaper(current);
876926
return true;
877927
}
878928

0 commit comments

Comments
 (0)