Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1325396 > unrolled thread
| Started by | Michal Hocko <mhocko@kernel.org> |
|---|---|
| First post | 2016-02-03 14:20 +0100 |
| Last post | 2016-02-06 15:40 +0100 |
| Articles | 9 on this page of 29 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH 0/5] oom reaper v5 Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
[PATCH 2/5] oom reaper: handle mlocked pages Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
Re: [PATCH 2/5] oom reaper: handle mlocked pages David Rientjes <rientjes@google.com> - 2016-02-04 01:00 +0100
[PATCH 4/5] mm, oom_reaper: report success/failure Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
Re: [PATCH 4/5] mm, oom_reaper: report success/failure David Rientjes <rientjes@google.com> - 2016-02-04 00:20 +0100
Re: [PATCH 4/5] mm, oom_reaper: report success/failure Michal Hocko <mhocko@kernel.org> - 2016-02-04 07:50 +0100
Re: [PATCH 4/5] mm, oom_reaper: report success/failure David Rientjes <rientjes@google.com> - 2016-02-04 23:40 +0100
Re: [PATCH 4/5] mm, oom_reaper: report success/failure Michal Hocko <mhocko@kernel.org> - 2016-02-05 10:30 +0100
Re: [PATCH 4/5] mm, oom_reaper: report success/failure Michal Hocko <mhocko@kernel.org> - 2016-02-06 07:40 +0100
[PATCH 1/5] mm, oom: introduce oom reaper Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
Re: [PATCH 1/5] mm, oom: introduce oom reaper David Rientjes <rientjes@google.com> - 2016-02-04 00:50 +0100
Re: [PATCH 1/5] mm, oom: introduce oom reaper Michal Hocko <mhocko@kernel.org> - 2016-02-04 07:50 +0100
Re: [PATCH 1/5] mm, oom: introduce oom reaper Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-06 14:30 +0100
[PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
Re: [PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-04 11:50 +0100
Re: [PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Michal Hocko <mhocko@kernel.org> - 2016-02-04 16:00 +0100
Re: [PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-06 07:00 +0100
Re: [PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Michal Hocko <mhocko@kernel.org> - 2016-02-06 09:40 +0100
Re: [PATCH 5/5] mm, oom_reaper: implement OOM victims queuing Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-06 16:40 +0100
[PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko <mhocko@kernel.org> - 2016-02-03 14:20 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-04 15:40 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko <mhocko@kernel.org> - 2016-02-04 15:50 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-04 16:10 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko <mhocko@kernel.org> - 2016-02-04 17:40 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-05 12:20 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko <mhocko@kernel.org> - 2016-02-06 09:40 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-06 12:30 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko <mhocko@kernel.org> - 2016-02-06 07:50 +0100
Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> - 2016-02-06 15:40 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2016-02-04 15:40 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qYteG-3bN-17@gated-at.bofh.it> |
| In reply to | #1325408 |
Michal Hocko wrote:
> From: Michal Hocko <mhocko@suse.com>
>
> When oom_reaper manages to unmap all the eligible vmas there shouldn't
> be much of the freable memory held by the oom victim left anymore so it
> makes sense to clear the TIF_MEMDIE flag for the victim and allow the
> OOM killer to select another task.
Just a confirmation. Is it safe to clear TIF_MEMDIE without reaching do_exit()
with regard to freezing_slow_path()? Since clearing TIF_MEMDIE from the OOM
reaper confuses
wait_event(oom_victims_wait, !atomic_read(&oom_victims));
in oom_killer_disable(), I'm worrying that the freezing operation continues
before the OOM victim which escaped the __refrigerator() actually releases
memory. Does this cause consistency problem?
> + /*
> + * Clear TIF_MEMDIE because the task shouldn't be sitting on a
> + * reasonably reclaimable memory anymore. OOM killer can continue
> + * by selecting other victim if unmapping hasn't led to any
> + * improvements. This also means that selecting this task doesn't
> + * make any sense.
> + */
> + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN;
> + exit_oom_victim(tsk);
I noticed that updating only one thread group's oom_score_adj disables
further wake_oom_reaper() calls due to rough-grained can_oom_reap check at
p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN
in oom_kill_process(). I think we need to either update all thread groups'
oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap
check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are
dying or exiting.
----------
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
static int writer(void *unused)
{
static char buffer[4096];
int fd = open("/tmp/file", O_WRONLY | O_CREAT | O_APPEND, 0600);
while (write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
return 0;
}
int main(int argc, char *argv[])
{
unsigned long size;
char *buf = NULL;
unsigned long i;
if (fork() == 0) {
int fd = open("/proc/self/oom_score_adj", O_WRONLY);
write(fd, "1000", 4);
close(fd);
for (i = 0; i < 2; i++) {
char *stack = malloc(4096);
if (stack)
clone(writer, stack + 4096, CLONE_VM, NULL);
}
writer(NULL);
while (1)
pause();
}
sleep(1);
for (size = 1048576; size < 512UL * (1 << 30); size <<= 1) {
char *cp = realloc(buf, size);
if (!cp) {
size >>= 1;
break;
}
buf = cp;
}
sleep(5);
/* Will cause OOM due to overcommit */
for (i = 0; i < size; i += 4096)
buf[i] = 0;
pause();
return 0;
}
----------
----------
[ 177.722853] a.out invoked oom-killer: gfp_mask=0x24280ca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), order=0, oom_score_adj=0
[ 177.724956] a.out cpuset=/ mems_allowed=0
[ 177.725735] CPU: 3 PID: 3962 Comm: a.out Not tainted 4.5.0-rc2-next-20160204 #291
(...snipped...)
[ 177.802889] [ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name
(...snipped...)
[ 177.872248] [ 3941] 1000 3941 28880 124 14 3 0 0 bash
[ 177.874279] [ 3962] 1000 3962 541717 395780 784 6 0 0 a.out
[ 177.876274] [ 3963] 1000 3963 1078 21 7 3 0 1000 a.out
[ 177.878261] [ 3964] 1000 3964 1078 21 7 3 0 1000 a.out
[ 177.880194] [ 3965] 1000 3965 1078 21 7 3 0 1000 a.out
[ 177.882262] Out of memory: Kill process 3963 (a.out) score 998 or sacrifice child
[ 177.884129] Killed process 3963 (a.out) total-vm:4312kB, anon-rss:84kB, file-rss:0kB, shmem-rss:0kB
[ 177.887100] oom_reaper: reaped process :3963 (a.out) anon-rss:0kB, file-rss:0kB, shmem-rss:0lB
[ 179.638399] crond invoked oom-killer: gfp_mask=0x24201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), order=0, oom_score_adj=0
[ 179.647708] crond cpuset=/ mems_allowed=0
[ 179.652996] CPU: 3 PID: 742 Comm: crond Not tainted 4.5.0-rc2-next-20160204 #291
(...snipped...)
[ 179.771311] [ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name
(...snipped...)
[ 179.836221] [ 3941] 1000 3941 28880 124 14 3 0 0 bash
[ 179.838278] [ 3962] 1000 3962 541717 396308 785 6 0 0 a.out
[ 179.840328] [ 3963] 1000 3963 1078 0 7 3 0 -1000 a.out
[ 179.842443] [ 3965] 1000 3965 1078 0 7 3 0 1000 a.out
[ 179.844557] Out of memory: Kill process 3965 (a.out) score 998 or sacrifice child
[ 179.846404] Killed process 3965 (a.out) total-vm:4312kB, anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
----------
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-02-04 15:50 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qYtol-3f9-1@gated-at.bofh.it> |
| In reply to | #1326872 |
On Thu 04-02-16 23:22:18, Tetsuo Handa wrote: > Michal Hocko wrote: > > From: Michal Hocko <mhocko@suse.com> > > > > When oom_reaper manages to unmap all the eligible vmas there shouldn't > > be much of the freable memory held by the oom victim left anymore so it > > makes sense to clear the TIF_MEMDIE flag for the victim and allow the > > OOM killer to select another task. > > Just a confirmation. Is it safe to clear TIF_MEMDIE without reaching do_exit() > with regard to freezing_slow_path()? Since clearing TIF_MEMDIE from the OOM > reaper confuses > > wait_event(oom_victims_wait, !atomic_read(&oom_victims)); > > in oom_killer_disable(), I'm worrying that the freezing operation continues > before the OOM victim which escaped the __refrigerator() actually releases > memory. Does this cause consistency problem? This is a good question! At first sight it seems this is not safe and we might need to make the oom_reaper freezable so that it doesn't wake up during suspend and interfere. Let me think about that. > > + /* > > + * Clear TIF_MEMDIE because the task shouldn't be sitting on a > > + * reasonably reclaimable memory anymore. OOM killer can continue > > + * by selecting other victim if unmapping hasn't led to any > > + * improvements. This also means that selecting this task doesn't > > + * make any sense. > > + */ > > + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN; > > + exit_oom_victim(tsk); > > I noticed that updating only one thread group's oom_score_adj disables > further wake_oom_reaper() calls due to rough-grained can_oom_reap check at > > p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN > > in oom_kill_process(). I think we need to either update all thread groups' > oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap > check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are > dying or exiting. I do not understand. Why would you want to reap the mm again when this has been done already? The mm is shared, right? -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2016-02-04 16:10 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qYtHH-3B3-5@gated-at.bofh.it> |
| In reply to | #1326883 |
Michal Hocko wrote: > > > + /* > > > + * Clear TIF_MEMDIE because the task shouldn't be sitting on a > > > + * reasonably reclaimable memory anymore. OOM killer can continue > > > + * by selecting other victim if unmapping hasn't led to any > > > + * improvements. This also means that selecting this task doesn't > > > + * make any sense. > > > + */ > > > + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN; > > > + exit_oom_victim(tsk); > > > > I noticed that updating only one thread group's oom_score_adj disables > > further wake_oom_reaper() calls due to rough-grained can_oom_reap check at > > > > p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN > > > > in oom_kill_process(). I think we need to either update all thread groups' > > oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap > > check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are > > dying or exiting. > > I do not understand. Why would you want to reap the mm again when > this has been done already? The mm is shared, right? The mm is shared between previous victim and next victim, but these victims are in different thread groups. The OOM killer selects next victim whose mm was already reaped due to sharing previous victim's memory. We don't want the OOM killer to select such next victim. Maybe set MMF_OOM_REAP_DONE on the previous victim's mm and check it instead of TIF_MEMDIE when selecting a victim? That will also avoid problems caused by clearing TIF_MEMDIE?
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-02-04 17:40 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qYv6P-4s9-31@gated-at.bofh.it> |
| In reply to | #1326901 |
On Fri 05-02-16 00:08:25, Tetsuo Handa wrote: > Michal Hocko wrote: > > > > + /* > > > > + * Clear TIF_MEMDIE because the task shouldn't be sitting on a > > > > + * reasonably reclaimable memory anymore. OOM killer can continue > > > > + * by selecting other victim if unmapping hasn't led to any > > > > + * improvements. This also means that selecting this task doesn't > > > > + * make any sense. > > > > + */ > > > > + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN; > > > > + exit_oom_victim(tsk); > > > > > > I noticed that updating only one thread group's oom_score_adj disables > > > further wake_oom_reaper() calls due to rough-grained can_oom_reap check at > > > > > > p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN > > > > > > in oom_kill_process(). I think we need to either update all thread groups' > > > oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap > > > check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are > > > dying or exiting. > > > > I do not understand. Why would you want to reap the mm again when > > this has been done already? The mm is shared, right? > > The mm is shared between previous victim and next victim, but these victims > are in different thread groups. The OOM killer selects next victim whose mm > was already reaped due to sharing previous victim's memory. OK, now I got your point. From your previous email it sounded like you were talking about oom_reaper and its invocation which is was confusing. > We don't want the OOM killer to select such next victim. Yes, selecting such a task doesn't make much sense. It has been killed so it has fatal_signal_pending. If it wanted to allocate it would get TIF_MEMDIE already and it's address space has been reaped so there is nothing to free left. These CLONE_VM without CLONE_SIGHAND is really crazy combo, it is just causing troubles all over and I am not convinced it is actually that helpful </rant>. > Maybe set MMF_OOM_REAP_DONE on > the previous victim's mm and check it instead of TIF_MEMDIE when selecting > a victim? That will also avoid problems caused by clearing TIF_MEMDIE? Hmm, it doesn't seem we are under MMF_ availabel bits pressure right now so using the flag sounds like the easiest way to go. Then we even do not have to play with OOM_SCORE_ADJ_MIN which might be updated from the userspace after the oom reaper has done that. Care to send a patch? Thanks! -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2016-02-05 12:20 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qYMAG-7S6-11@gated-at.bofh.it> |
| In reply to | #1326989 |
Michal Hocko wrote:
> On Fri 05-02-16 00:08:25, Tetsuo Handa wrote:
> > Michal Hocko wrote:
> > > > > + /*
> > > > > + * Clear TIF_MEMDIE because the task shouldn't be sitting on a
> > > > > + * reasonably reclaimable memory anymore. OOM killer can continue
> > > > > + * by selecting other victim if unmapping hasn't led to any
> > > > > + * improvements. This also means that selecting this task doesn't
> > > > > + * make any sense.
> > > > > + */
> > > > > + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN;
> > > > > + exit_oom_victim(tsk);
> > > >
> > > > I noticed that updating only one thread group's oom_score_adj disables
> > > > further wake_oom_reaper() calls due to rough-grained can_oom_reap check at
> > > >
> > > > p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN
> > > >
> > > > in oom_kill_process(). I think we need to either update all thread groups'
> > > > oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap
> > > > check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are
> > > > dying or exiting.
> > >
> > > I do not understand. Why would you want to reap the mm again when
> > > this has been done already? The mm is shared, right?
> >
> > The mm is shared between previous victim and next victim, but these victims
> > are in different thread groups. The OOM killer selects next victim whose mm
> > was already reaped due to sharing previous victim's memory.
>
> OK, now I got your point. From your previous email it sounded like you
> were talking about oom_reaper and its invocation which is was confusing.
>
> > We don't want the OOM killer to select such next victim.
>
> Yes, selecting such a task doesn't make much sense. It has been killed
> so it has fatal_signal_pending. If it wanted to allocate it would get
> TIF_MEMDIE already and it's address space has been reaped so there is
> nothing to free left. These CLONE_VM without CLONE_SIGHAND is really
> crazy combo, it is just causing troubles all over and I am not convinced
> it is actually that helpful </rant>.
>
I think moving "whether a mm is reapable or not" check to the OOM reaper
is preferable (shown below). In most cases, mm_is_reapable() will return
true.
----------------------------------------
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index b42c6bc..fc114b3 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -426,6 +426,39 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
static LIST_HEAD(oom_reaper_list);
static DEFINE_SPINLOCK(oom_reaper_lock);
+static bool mm_is_reapable(struct mm_struct *mm)
+{
+ struct task_struct *g;
+ struct task_struct *p;
+
+ /*
+ * Since it is possible that p voluntarily called do_exit() or
+ * somebody other than the OOM killer sent SIGKILL on p, this mm used
+ * by p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN is reapable if p
+ * has pending SIGKILL or already reached do_exit().
+ *
+ * On the other hand, it is possible that mark_oom_victim(p) is called
+ * without sending SIGKILL to all tasks using this mm. In this case,
+ * the OOM reaper cannot reap this mm unless p is the only task using
+ * this mm.
+ *
+ * Therefore, determine whether this mm is reapable by testing whether
+ * all tasks using this mm are dying or already exiting rather than
+ * depending on p->signal->oom_score_adj value which is updated by the
+ * OOM reaper.
+ */
+ rcu_read_lock();
+ for_each_process_thread(g, p) {
+ if (mm != READ_ONCE(p->mm) ||
+ fatal_signal_pending(p) || (p->flags & PF_EXITING))
+ continue;
+ mm = NULL;
+ goto out;
+ }
+ out:
+ rcu_read_unlock();
+ return mm != NULL;
+}
static bool __oom_reap_task(struct task_struct *tsk)
{
@@ -455,7 +488,7 @@ static bool __oom_reap_task(struct task_struct *tsk)
task_unlock(p);
- if (!down_read_trylock(&mm->mmap_sem)) {
+ if (!mm_is_reapable(mm) || !down_read_trylock(&mm->mmap_sem)) {
ret = false;
goto out;
}
@@ -596,6 +629,7 @@ void mark_oom_victim(struct task_struct *tsk)
*/
__thaw_task(tsk);
atomic_inc(&oom_victims);
+ wake_oom_reaper(tsk);
}
/**
@@ -680,7 +714,6 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
unsigned int victim_points = 0;
static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
- bool can_oom_reap = true;
/*
* If the task is already exiting, don't alarm the sysadmin or kill
@@ -771,23 +804,17 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
continue;
if (same_thread_group(p, victim))
continue;
- if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p) ||
- p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
- /*
- * We cannot use oom_reaper for the mm shared by this
- * process because it wouldn't get killed and so the
- * memory might be still used.
- */
- can_oom_reap = false;
+ if (unlikely(p->flags & PF_KTHREAD))
continue;
- }
+ if (is_global_init(p))
+ continue;
+ if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
+ continue;
+
do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
}
rcu_read_unlock();
- if (can_oom_reap)
- wake_oom_reaper(victim);
-
mmdrop(mm);
put_task_struct(victim);
}
----------------------------------------
Then, I think we need to kill two lies in allocation retry loop.
The first lie is that we pretend as if we are making forward progress
without hitting the OOM killer. This lie is preventing any OOM victim
(with SIGKILL and without TIF_MEMDIE) doing !__GFP_FS allocations from
hitting the OOM killer, which can prevent the OOM victim tasks from
reaching do_exit(), and which is conflicting with assumption
* That thread will now get access to memory reserves since it has a
* pending fatal signal.
in oom_kill_process() and similar assertions like this patch's description.
The lack of TIF_MEMDIE also means that the victim cannot access memory
reserves anymore but that shouldn't be a problem because it would get
the access again if it needs to allocate and hits the OOM killer again
due to the fatal_signal_pending resp. PF_EXITING check.
If the callers of !__GFP_FS allocation do not need to loop until somebody
else reclaims memory on behalf of them, they can add __GFP_NORETRY. Otherwise,
the callers of !__GFP_FS allocation can and should call out_of_memory().
That's all we need for killing this lie.
----------------------------------------
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 1668159..67591a0 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2772,20 +2772,6 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
/* The OOM killer does not needlessly kill tasks for lowmem */
if (ac->high_zoneidx < ZONE_NORMAL)
goto out;
- /* The OOM killer does not compensate for IO-less reclaim */
- if (!(gfp_mask & __GFP_FS)) {
- /*
- * XXX: Page reclaim didn't yield anything,
- * and the OOM killer can't be invoked, but
- * keep looping as per tradition.
- *
- * But do not keep looping if oom_killer_disable()
- * was already called, for the system is trying to
- * enter a quiescent state during suspend.
- */
- *did_some_progress = !oom_killer_disabled;
- goto out;
- }
if (pm_suspended_storage())
goto out;
/* The OOM killer may not free memory on a specific node */
----------------------------------------
The second lie is that we pretend as if we are making forward progress
without taking any action when the OOM killer found a TIF_MEMDIE task.
This lie is preventing any task (without SIGKILL and without TIF_MEMDIE)
which is blocking the OOM victim (which might be looping without getting
TIF_MEMDIE due to doing !__GFP_FS allocation) from making forward progress
if the OOM reaper does not clear TIF_MEMDIE.
----------------------------------------
/* Retry as long as the OOM killer is making progress */
if (did_some_progress) {
no_progress_loops = 0;
goto retry;
}
----------------------------------------
v.s.
----------------------------------------
/*
* This task already has access to memory reserves and is being killed.
* Don't allow any other task to have access to the reserves.
*/
if (test_tsk_thread_flag(task, TIF_MEMDIE)) {
if (!is_sysrq_oom(oc))
return OOM_SCAN_ABORT;
}
----------------------------------------
By moving "whether a mm is reapable or not" check to the OOM reaper, we can
delegate the duty of clearing TIF_MEMDIE to the OOM reaper because the OOM
reaper is tracking all TIF_MEMDIE tasks. Since mm_is_reapable() can return
true for most situations, it becomes an unlikely corner case that we need to
clear TIF_MEMDIE and prevent the OOM killer from setting TIF_MEMDIE on the
same task again when the OOM reaper gave up. Like you commented in [PATCH 5/5],
falling back to simple timer would be sufficient for handling such corner cases.
| I would really prefer to go a simpler way first and extend the code when
| we see the current approach insufficient for real life loads. Please do
| not get me wrong, of course the code can be enhanced in many different
| ways and optimize for lots of pathological cases but I really believe
| that we should start with correctness first and only later care about
| optimizing corner cases.
>
> > Maybe set MMF_OOM_REAP_DONE on
> > the previous victim's mm and check it instead of TIF_MEMDIE when selecting
> > a victim? That will also avoid problems caused by clearing TIF_MEMDIE?
>
> Hmm, it doesn't seem we are under MMF_ availabel bits pressure right now
> so using the flag sounds like the easiest way to go. Then we even do not
> have to play with OOM_SCORE_ADJ_MIN which might be updated from the
> userspace after the oom reaper has done that. Care to send a patch?
Not only we don't need to worry about ->oom_score_adj being modified from
outside the SIGKILL pending tasks, I think we also don't need to clear remote
TIF_MEMDIE if we use MMF_OOM_REAP_DONE. Something like below untested patch?
----------------------------------------
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 45993b8..03e6257 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -91,7 +91,7 @@ extern enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
extern bool out_of_memory(struct oom_control *oc);
-extern void exit_oom_victim(struct task_struct *tsk);
+extern void exit_oom_victim(void);
extern int register_oom_notifier(struct notifier_block *nb);
extern int unregister_oom_notifier(struct notifier_block *nb);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 012dd6f..442ba46 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -515,6 +515,8 @@ static inline int get_dumpable(struct mm_struct *mm)
#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
+#define MMF_OOM_REAP_DONE 21 /* set when OOM reap completed */
+
struct sighand_struct {
atomic_t count;
struct k_sigaction action[_NSIG];
diff --git a/kernel/exit.c b/kernel/exit.c
index ba3bd29..10e0882 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -434,7 +434,7 @@ static void exit_mm(struct task_struct *tsk)
mm_update_next_owner(mm);
mmput(mm);
if (test_thread_flag(TIF_MEMDIE))
- exit_oom_victim(tsk);
+ exit_oom_victim();
}
static struct task_struct *find_alive_thread(struct task_struct *p)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index b42c6bc..b67d8bf 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -271,19 +271,24 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc,
enum oom_scan_t oom_scan_process_thread(struct oom_control *oc,
struct task_struct *task, unsigned long totalpages)
{
+ struct mm_struct *mm;
+
if (oom_unkillable_task(task, NULL, oc->nodemask))
return OOM_SCAN_CONTINUE;
+ mm = task->mm;
+ if (!mm)
+ 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.
+ * Don't allow any other task to have access to the reserves unless
+ * this task's memory was OOM reaped.
*/
if (test_tsk_thread_flag(task, TIF_MEMDIE)) {
- if (!is_sysrq_oom(oc))
+ if (!is_sysrq_oom(oc) &&
+ !test_bit(MMF_OOM_REAP_DONE, &mm->flags))
return OOM_SCAN_ABORT;
}
- if (!task->mm)
- return OOM_SCAN_CONTINUE;
/*
* If task is allocating a lot of memory and has been marked to be
@@ -448,7 +453,8 @@ static bool __oom_reap_task(struct task_struct *tsk)
return true;
mm = p->mm;
- if (!atomic_inc_not_zero(&mm->mm_users)) {
+ if (test_bit(MMF_OOM_REAP_DONE, &mm->flags) ||
+ !atomic_inc_not_zero(&mm->mm_users)) {
task_unlock(p);
return true;
}
@@ -491,14 +497,11 @@ static bool __oom_reap_task(struct task_struct *tsk)
up_read(&mm->mmap_sem);
/*
- * Clear TIF_MEMDIE because the task shouldn't be sitting on a
- * reasonably reclaimable memory anymore. OOM killer can continue
- * by selecting other victim if unmapping hasn't led to any
- * improvements. This also means that selecting this task doesn't
- * make any sense.
+ * Set MMF_OOM_REAP_DONE on this mm so that OOM killer can continue
+ * by selecting other victim which does not use this mm if unmapping
+ * this mm hasn't led to any improvements.
*/
- tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN;
- exit_oom_victim(tsk);
+ set_bit(MMF_OOM_REAP_DONE, &mm->flags);
out:
mmput(mm);
return ret;
@@ -601,10 +604,9 @@ void mark_oom_victim(struct task_struct *tsk)
/**
* exit_oom_victim - note the exit of an OOM victim
*/
-void exit_oom_victim(struct task_struct *tsk)
+void exit_oom_victim(void)
{
- if (!test_and_clear_tsk_thread_flag(tsk, TIF_MEMDIE))
- return;
+ clear_thread_flag(TIF_MEMDIE);
if (!atomic_dec_return(&oom_victims))
wake_up_all(&oom_victims_wait);
----------------------------------------
I suggested many changes in this post because [PATCH 3/5] and [PATCH 5/5]
made it possible for us to simplify [PATCH 1/5] like old versions. I think
you want to rebuild this series with these changes merged as appropriate.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-02-06 09:40 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qZ6zo-4Gj-5@gated-at.bofh.it> |
| In reply to | #1327608 |
On Fri 05-02-16 20:14:40, Tetsuo Handa wrote:
> Michal Hocko wrote:
> > On Fri 05-02-16 00:08:25, Tetsuo Handa wrote:
> > > Michal Hocko wrote:
> > > > > > + /*
> > > > > > + * Clear TIF_MEMDIE because the task shouldn't be sitting on a
> > > > > > + * reasonably reclaimable memory anymore. OOM killer can continue
> > > > > > + * by selecting other victim if unmapping hasn't led to any
> > > > > > + * improvements. This also means that selecting this task doesn't
> > > > > > + * make any sense.
> > > > > > + */
> > > > > > + tsk->signal->oom_score_adj = OOM_SCORE_ADJ_MIN;
> > > > > > + exit_oom_victim(tsk);
> > > > >
> > > > > I noticed that updating only one thread group's oom_score_adj disables
> > > > > further wake_oom_reaper() calls due to rough-grained can_oom_reap check at
> > > > >
> > > > > p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN
> > > > >
> > > > > in oom_kill_process(). I think we need to either update all thread groups'
> > > > > oom_score_adj using the reaped mm equally or use more fine-grained can_oom_reap
> > > > > check which ignores OOM_SCORE_ADJ_MIN if all threads in that thread group are
> > > > > dying or exiting.
> > > >
> > > > I do not understand. Why would you want to reap the mm again when
> > > > this has been done already? The mm is shared, right?
> > >
> > > The mm is shared between previous victim and next victim, but these victims
> > > are in different thread groups. The OOM killer selects next victim whose mm
> > > was already reaped due to sharing previous victim's memory.
> >
> > OK, now I got your point. From your previous email it sounded like you
> > were talking about oom_reaper and its invocation which is was confusing.
> >
> > > We don't want the OOM killer to select such next victim.
> >
> > Yes, selecting such a task doesn't make much sense. It has been killed
> > so it has fatal_signal_pending. If it wanted to allocate it would get
> > TIF_MEMDIE already and it's address space has been reaped so there is
> > nothing to free left. These CLONE_VM without CLONE_SIGHAND is really
> > crazy combo, it is just causing troubles all over and I am not convinced
> > it is actually that helpful </rant>.
> >
>
> I think moving "whether a mm is reapable or not" check to the OOM reaper
> is preferable (shown below). In most cases, mm_is_reapable() will return
> true.
Why should we select such a task in the first place when it's been
already oom reaped? I think it belongs to oom_scan_process_thread.
> ----------------------------------------
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index b42c6bc..fc114b3 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -426,6 +426,39 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
> static LIST_HEAD(oom_reaper_list);
> static DEFINE_SPINLOCK(oom_reaper_lock);
>
> +static bool mm_is_reapable(struct mm_struct *mm)
> +{
> + struct task_struct *g;
> + struct task_struct *p;
> +
> + /*
> + * Since it is possible that p voluntarily called do_exit() or
> + * somebody other than the OOM killer sent SIGKILL on p, this mm used
> + * by p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN is reapable if p
> + * has pending SIGKILL or already reached do_exit().
> + *
> + * On the other hand, it is possible that mark_oom_victim(p) is called
> + * without sending SIGKILL to all tasks using this mm. In this case,
> + * the OOM reaper cannot reap this mm unless p is the only task using
> + * this mm.
> + *
> + * Therefore, determine whether this mm is reapable by testing whether
> + * all tasks using this mm are dying or already exiting rather than
> + * depending on p->signal->oom_score_adj value which is updated by the
> + * OOM reaper.
> + */
> + rcu_read_lock();
> + for_each_process_thread(g, p) {
> + if (mm != READ_ONCE(p->mm) ||
> + fatal_signal_pending(p) || (p->flags & PF_EXITING))
> + continue;
> + mm = NULL;
> + goto out;
> + }
> + out:
> + rcu_read_unlock();
> + return mm != NULL;
> +}
>
> static bool __oom_reap_task(struct task_struct *tsk)
> {
> @@ -455,7 +488,7 @@ static bool __oom_reap_task(struct task_struct *tsk)
>
> task_unlock(p);
>
> - if (!down_read_trylock(&mm->mmap_sem)) {
> + if (!mm_is_reapable(mm) || !down_read_trylock(&mm->mmap_sem)) {
> ret = false;
> goto out;
> }
> @@ -596,6 +629,7 @@ void mark_oom_victim(struct task_struct *tsk)
> */
> __thaw_task(tsk);
> atomic_inc(&oom_victims);
> + wake_oom_reaper(tsk);
> }
>
> /**
> @@ -680,7 +714,6 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
> unsigned int victim_points = 0;
> static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
> DEFAULT_RATELIMIT_BURST);
> - bool can_oom_reap = true;
>
> /*
> * If the task is already exiting, don't alarm the sysadmin or kill
> @@ -771,23 +804,17 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
> continue;
> if (same_thread_group(p, victim))
> continue;
> - if (unlikely(p->flags & PF_KTHREAD) || is_global_init(p) ||
> - p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
> - /*
> - * We cannot use oom_reaper for the mm shared by this
> - * process because it wouldn't get killed and so the
> - * memory might be still used.
> - */
> - can_oom_reap = false;
> + if (unlikely(p->flags & PF_KTHREAD))
> continue;
> - }
> + if (is_global_init(p))
> + continue;
> + if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
> + continue;
> +
> do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
> }
> rcu_read_unlock();
>
> - if (can_oom_reap)
> - wake_oom_reaper(victim);
> -
> mmdrop(mm);
> put_task_struct(victim);
> }
> ----------------------------------------
this is unnecessarily too complex IMO
> Then, I think we need to kill two lies in allocation retry loop.
This is completely unrelated to the topic discussed here.
[...]
> By moving "whether a mm is reapable or not" check to the OOM reaper, we can
> delegate the duty of clearing TIF_MEMDIE to the OOM reaper because the OOM
> reaper is tracking all TIF_MEMDIE tasks. Since mm_is_reapable() can return
> true for most situations, it becomes an unlikely corner case that we need to
> clear TIF_MEMDIE and prevent the OOM killer from setting TIF_MEMDIE on the
> same task again when the OOM reaper gave up. Like you commented in [PATCH 5/5],
> falling back to simple timer would be sufficient for handling such corner cases.
I am not really sure I understand what you are trying to tell here to be honest
but no I am not going to add any timers at this stage.
> | I would really prefer to go a simpler way first and extend the code when
> | we see the current approach insufficient for real life loads. Please do
> | not get me wrong, of course the code can be enhanced in many different
> | ways and optimize for lots of pathological cases but I really believe
> | that we should start with correctness first and only later care about
> | optimizing corner cases.
>
> >
> > > Maybe set MMF_OOM_REAP_DONE on
> > > the previous victim's mm and check it instead of TIF_MEMDIE when selecting
> > > a victim? That will also avoid problems caused by clearing TIF_MEMDIE?
> >
> > Hmm, it doesn't seem we are under MMF_ availabel bits pressure right now
> > so using the flag sounds like the easiest way to go. Then we even do not
> > have to play with OOM_SCORE_ADJ_MIN which might be updated from the
> > userspace after the oom reaper has done that. Care to send a patch?
>
> Not only we don't need to worry about ->oom_score_adj being modified from
> outside the SIGKILL pending tasks, I think we also don't need to clear remote
> TIF_MEMDIE if we use MMF_OOM_REAP_DONE. Something like below untested patch?
Dropping TIF_MEMDIE will help to unlock OOM killer as soon as we know
the current victim is no longer interesting for the OOM killer to allow
further victims selection. If we add MMF_OOM_REAP_DONE after reaping and
oom_scan_process_thread is taught to ignore those you will get all cases
of shared memory handles properly AFAICS. Such a patch should be really
trivial enhancement on top of the current code.
[...]
> I suggested many changes in this post because [PATCH 3/5] and [PATCH 5/5]
> made it possible for us to simplify [PATCH 1/5] like old versions. I think
> you want to rebuild this series with these changes merged as appropriate.
I would really _appreciate_ incremental changes as mentioned several
times already. And it would be really helpful if you could stick to
that. If you want to propose additional enhancements on top of the
current code you are free to do so but I am really reluctant to respin
everything to add more stuff into each patch and risk introduction of new
bugs. As things stand now patches are aiming to be as simple as possible
they do not introduce new bugs (except for the PM freezer which should
be fixable by a trivial patch which I will post after I get back from
vacation) and they improve things considerably in its current form
already.
I would like to target the next merge window rather than have this out
of tree for another release cycle which means that we should really
focus on the current functionality and make sure we haven't missed
anything. As there is no fundamental disagreement to the approach all
the rest are just technicalities.
Thanks
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2016-02-06 12:30 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qZ9dT-6zf-3@gated-at.bofh.it> |
| In reply to | #1328262 |
Michal Hocko wrote:
> I am not really sure I understand what you are trying to tell here to be honest
> but no I am not going to add any timers at this stage.
> Dropping TIF_MEMDIE will help to unlock OOM killer as soon as we know
> the current victim is no longer interesting for the OOM killer to allow
> further victims selection. If we add MMF_OOM_REAP_DONE after reaping and
> oom_scan_process_thread is taught to ignore those you will get all cases
> of shared memory handles properly AFAICS. Such a patch should be really
> trivial enhancement on top of the current code.
What I'm trying to tell is that we should prepare for corner cases where
dropping TIF_MEMDIE (or reaping the victim's memory) is not taken place.
What happens if TIF_MEMDIE was set at
if (current->mm &&
(fatal_signal_pending(current) || task_will_free_mem(current))) {
mark_oom_victim(current);
return true;
}
in out_of_memory() because current thread received SIGKILL while doing
a GFP_KERNEL allocation of
Do a GFP_KERNEL allocation.
Bail out if GFP_KERNEL allocation failed.
Hold a lock.
Do a GFP_NOFS allocation.
Release a lock.
sequence? If current thread is blocked at waiting for that lock held by
somebody else doing memory allocation, nothing will unlock the OOM killer
(because the OOM reaper is not woken up and a timer for unlocking the OOM
killer does not exist).
What happens if TIF_MEMDIE was set at
task_lock(p);
if (p->mm && task_will_free_mem(p)) {
mark_oom_victim(p);
task_unlock(p);
put_task_struct(p);
return;
}
task_unlock(p);
in oom_kill_process() when p is waiting for a lock held by somebody else
doing memory allocation? Since the OOM reaper will not be woken up,
nothing will unlock the OOM killer.
If TIF_MEMDIE was set at
do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);
mark_oom_victim(victim);
pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
in oom_kill_process() but the OOM reaper was not woken up because of
p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN case, nothing will unlock
the OOM killer.
By always waking the OOM reaper up, we can delegate the duty of unlocking
the OOM killer (by clearing TIF_MEMDIE or some other means) to the OOM
reaper because the OOM reaper is tracking all TIF_MEMDIE tasks.
Of course, it is possible that we handle such corner cases by adding
a timer for unlocking the OOM killer (regardless of availability of the
OOM reaper). But if we do "whether a mm is reapable or not" check at the
OOM reaper side by waking the OOM reaper up whenever TIF_MEMDIE is set
on some task, we can increase likeliness of dropping TIF_MEMDIE (after
reaping the victim's memory) being taken place and reduce frequency of
killing more OOM victims by using a timer for unlocking the OOM killer.
> I would like to target the next merge window rather than have this out
> of tree for another release cycle which means that we should really
> focus on the current functionality and make sure we haven't missed
> anything. As there is no fundamental disagreement to the approach all
> the rest are just technicalities.
Of course, we can target the OOM reaper for the next merge window. I'm
suggesting you that my changes would help handling corner cases (bugs)
you are not paying attention to.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2016-02-06 07:50 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qZ4QV-3pG-5@gated-at.bofh.it> |
| In reply to | #1326883 |
On Thu 04-02-16 15:43:19, Michal Hocko wrote:
> On Thu 04-02-16 23:22:18, Tetsuo Handa wrote:
> > Michal Hocko wrote:
> > > From: Michal Hocko <mhocko@suse.com>
> > >
> > > When oom_reaper manages to unmap all the eligible vmas there shouldn't
> > > be much of the freable memory held by the oom victim left anymore so it
> > > makes sense to clear the TIF_MEMDIE flag for the victim and allow the
> > > OOM killer to select another task.
> >
> > Just a confirmation. Is it safe to clear TIF_MEMDIE without reaching do_exit()
> > with regard to freezing_slow_path()? Since clearing TIF_MEMDIE from the OOM
> > reaper confuses
> >
> > wait_event(oom_victims_wait, !atomic_read(&oom_victims));
> >
> > in oom_killer_disable(), I'm worrying that the freezing operation continues
> > before the OOM victim which escaped the __refrigerator() actually releases
> > memory. Does this cause consistency problem?
>
> This is a good question! At first sight it seems this is not safe and we
> might need to make the oom_reaper freezable so that it doesn't wake up
> during suspend and interfere. Let me think about that.
OK, I was thinking about it some more and it seems you are right here.
oom_reaper as a kernel thread is not freezable automatically and so it
might interfere after all the processes/kernel threads are considered
frozen. Then it really might shut down TIF_MEMDIE too early and wake out
oom_killer_disable. wait_event_freezable is not sufficient because the
oom_reaper might running while the PM freezer is freezing tasks and it
will miss it because it doesn't see it.
So I think we might need this. I am heading to vacation today and will
be offline for the next week so I will prepare the full patch with the
proper changelog after I get back:
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index ca61e6cfae52..7e9953a64489 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -521,6 +521,8 @@ static void oom_reap_task(struct task_struct *tsk)
static int oom_reaper(void *unused)
{
+ set_freezable();
+
while (true) {
struct task_struct *tsk = NULL;
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
|---|---|
| Date | 2016-02-06 15:40 +0100 |
| Subject | Re: [PATCH 3/5] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space |
| Message-ID | <qZcbN-6L-29@gated-at.bofh.it> |
| In reply to | #1328236 |
Michal Hocko wrote:
> On Thu 04-02-16 15:43:19, Michal Hocko wrote:
> > On Thu 04-02-16 23:22:18, Tetsuo Handa wrote:
> > > Michal Hocko wrote:
> > > > From: Michal Hocko <mhocko@suse.com>
> > > >
> > > > When oom_reaper manages to unmap all the eligible vmas there shouldn't
> > > > be much of the freable memory held by the oom victim left anymore so it
> > > > makes sense to clear the TIF_MEMDIE flag for the victim and allow the
> > > > OOM killer to select another task.
> > >
> > > Just a confirmation. Is it safe to clear TIF_MEMDIE without reaching do_exit()
> > > with regard to freezing_slow_path()? Since clearing TIF_MEMDIE from the OOM
> > > reaper confuses
> > >
> > > wait_event(oom_victims_wait, !atomic_read(&oom_victims));
> > >
> > > in oom_killer_disable(), I'm worrying that the freezing operation continues
> > > before the OOM victim which escaped the __refrigerator() actually releases
> > > memory. Does this cause consistency problem?
> >
> > This is a good question! At first sight it seems this is not safe and we
> > might need to make the oom_reaper freezable so that it doesn't wake up
> > during suspend and interfere. Let me think about that.
>
> OK, I was thinking about it some more and it seems you are right here.
> oom_reaper as a kernel thread is not freezable automatically and so it
> might interfere after all the processes/kernel threads are considered
> frozen. Then it really might shut down TIF_MEMDIE too early and wake out
> oom_killer_disable. wait_event_freezable is not sufficient because the
> oom_reaper might running while the PM freezer is freezing tasks and it
> will miss it because it doesn't see it.
I'm not using PM freezer, but your answer is opposite to my guess.
I thought try_to_freeze_tasks(false) is called by freeze_kernel_threads()
after oom_killer_disable() succeeded, and try_to_freeze_tasks(false) will
freeze both userspace tasks (including OOM victims which got TIF_MEMDIE
cleared by the OOM reaper) and kernel threads (including the OOM reaper).
Thus, I was guessing that clearing TIF_MEMDIE without reaching do_exit() is
safe.
>
> So I think we might need this. I am heading to vacation today and will
> be offline for the next week so I will prepare the full patch with the
> proper changelog after I get back:
>
I can't judge whether we need this set_freezable().
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index ca61e6cfae52..7e9953a64489 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -521,6 +521,8 @@ static void oom_reap_task(struct task_struct *tsk)
>
> static int oom_reaper(void *unused)
> {
> + set_freezable();
> +
> while (true) {
> struct task_struct *tsk = NULL;
>
> --
> Michal Hocko
> SUSE Labs
>
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web