From: Michal Hocko <mhocko@kernel.org> To: Andrew Morton <akpm@linux-foundation.org> Cc: <linux-mm@kvack.org>, LKML <linux-kernel@vger.kernel.org>, Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>, David Rientjes <rientjes@google.com>, Michal Hocko <mhocko@suse.com> Subject: [PATCH 5/9] mm, oom_reaper: implement OOM victims queuing Date: Tue, 22 Mar 2016 12:00:22 +0100 [thread overview] Message-ID: <1458644426-22973-6-git-send-email-mhocko@kernel.org> (raw) In-Reply-To: <1458644426-22973-1-git-send-email-mhocko@kernel.org> From: Michal Hocko <mhocko@suse.com> wake_oom_reaper has allowed only 1 oom victim to be queued. The main reason for that was the simplicity as other solutions would require some way of queuing. The current approach is racy and that was deemed sufficient as the oom_reaper is considered a best effort approach to help with oom handling when the OOM victim cannot terminate in a reasonable time. The race could lead to missing an oom victim which can get stuck out_of_memory wake_oom_reaper cmpxchg // OK oom_reaper oom_reap_task __oom_reap_task oom_victim terminates atomic_inc_not_zero // fail out_of_memory wake_oom_reaper cmpxchg // fails task_to_reap = NULL This race requires 2 OOM invocations in a short time period which is not very likely but certainly not impossible. E.g. the original victim might have not released a lot of memory for some reason. The situation would improve considerably if wake_oom_reaper used a more robust queuing. This is what this patch implements. This means adding oom_reaper_list list_head into task_struct (eat a hole before embeded thread_struct for that purpose) and a oom_reaper_lock spinlock for queuing synchronization. wake_oom_reaper will then add the task on the queue and oom_reaper will dequeue it. Signed-off-by: Michal Hocko <mhocko@suse.com> --- include/linux/sched.h | 3 +++ mm/oom_kill.c | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 9cf5731472fe..bc5867296f7b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1838,6 +1838,9 @@ struct task_struct { unsigned long task_state_change; #endif int pagefault_disabled; +#ifdef CONFIG_MMU + struct list_head oom_reaper_list; +#endif /* CPU-specific state of this task */ struct thread_struct thread; /* diff --git a/mm/oom_kill.c b/mm/oom_kill.c index e627ce235e38..8e0bd279135f 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -416,8 +416,10 @@ bool oom_killer_disabled __read_mostly; * victim (if that is possible) to help the OOM killer to move on. */ static struct task_struct *oom_reaper_th; -static struct task_struct *task_to_reap; static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait); +static LIST_HEAD(oom_reaper_list); +static DEFINE_SPINLOCK(oom_reaper_lock); + #define K(x) ((x) << (PAGE_SHIFT-10)) static bool __oom_reap_task(struct task_struct *tsk) @@ -523,12 +525,20 @@ static void oom_reap_task(struct task_struct *tsk) static int oom_reaper(void *unused) { while (true) { - struct task_struct *tsk; + struct task_struct *tsk = NULL; wait_event_freezable(oom_reaper_wait, - (tsk = READ_ONCE(task_to_reap))); - oom_reap_task(tsk); - WRITE_ONCE(task_to_reap, NULL); + (!list_empty(&oom_reaper_list))); + spin_lock(&oom_reaper_lock); + if (!list_empty(&oom_reaper_list)) { + tsk = list_first_entry(&oom_reaper_list, + struct task_struct, oom_reaper_list); + list_del(&tsk->oom_reaper_list); + } + spin_unlock(&oom_reaper_lock); + + if (tsk) + oom_reap_task(tsk); } return 0; @@ -536,23 +546,15 @@ static int oom_reaper(void *unused) static void wake_oom_reaper(struct task_struct *tsk) { - struct task_struct *old_tsk; - if (!oom_reaper_th) return; get_task_struct(tsk); - /* - * Make sure that only a single mm is ever queued for the reaper - * because multiple are not necessary and the operation might be - * disruptive so better reduce it to the bare minimum. - */ - old_tsk = cmpxchg(&task_to_reap, NULL, tsk); - if (!old_tsk) - wake_up(&oom_reaper_wait); - else - put_task_struct(tsk); + spin_lock(&oom_reaper_lock); + list_add(&tsk->oom_reaper_list, &oom_reaper_list); + spin_unlock(&oom_reaper_lock); + wake_up(&oom_reaper_wait); } static int __init oom_init(void) -- 2.7.0
WARNING: multiple messages have this Message-ID (diff)
From: Michal Hocko <mhocko@kernel.org> To: Andrew Morton <akpm@linux-foundation.org> Cc: linux-mm@kvack.org, LKML <linux-kernel@vger.kernel.org>, Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>, David Rientjes <rientjes@google.com>, Michal Hocko <mhocko@suse.com> Subject: [PATCH 5/9] mm, oom_reaper: implement OOM victims queuing Date: Tue, 22 Mar 2016 12:00:22 +0100 [thread overview] Message-ID: <1458644426-22973-6-git-send-email-mhocko@kernel.org> (raw) In-Reply-To: <1458644426-22973-1-git-send-email-mhocko@kernel.org> From: Michal Hocko <mhocko@suse.com> wake_oom_reaper has allowed only 1 oom victim to be queued. The main reason for that was the simplicity as other solutions would require some way of queuing. The current approach is racy and that was deemed sufficient as the oom_reaper is considered a best effort approach to help with oom handling when the OOM victim cannot terminate in a reasonable time. The race could lead to missing an oom victim which can get stuck out_of_memory wake_oom_reaper cmpxchg // OK oom_reaper oom_reap_task __oom_reap_task oom_victim terminates atomic_inc_not_zero // fail out_of_memory wake_oom_reaper cmpxchg // fails task_to_reap = NULL This race requires 2 OOM invocations in a short time period which is not very likely but certainly not impossible. E.g. the original victim might have not released a lot of memory for some reason. The situation would improve considerably if wake_oom_reaper used a more robust queuing. This is what this patch implements. This means adding oom_reaper_list list_head into task_struct (eat a hole before embeded thread_struct for that purpose) and a oom_reaper_lock spinlock for queuing synchronization. wake_oom_reaper will then add the task on the queue and oom_reaper will dequeue it. Signed-off-by: Michal Hocko <mhocko@suse.com> --- include/linux/sched.h | 3 +++ mm/oom_kill.c | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 9cf5731472fe..bc5867296f7b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1838,6 +1838,9 @@ struct task_struct { unsigned long task_state_change; #endif int pagefault_disabled; +#ifdef CONFIG_MMU + struct list_head oom_reaper_list; +#endif /* CPU-specific state of this task */ struct thread_struct thread; /* diff --git a/mm/oom_kill.c b/mm/oom_kill.c index e627ce235e38..8e0bd279135f 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -416,8 +416,10 @@ bool oom_killer_disabled __read_mostly; * victim (if that is possible) to help the OOM killer to move on. */ static struct task_struct *oom_reaper_th; -static struct task_struct *task_to_reap; static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait); +static LIST_HEAD(oom_reaper_list); +static DEFINE_SPINLOCK(oom_reaper_lock); + #define K(x) ((x) << (PAGE_SHIFT-10)) static bool __oom_reap_task(struct task_struct *tsk) @@ -523,12 +525,20 @@ static void oom_reap_task(struct task_struct *tsk) static int oom_reaper(void *unused) { while (true) { - struct task_struct *tsk; + struct task_struct *tsk = NULL; wait_event_freezable(oom_reaper_wait, - (tsk = READ_ONCE(task_to_reap))); - oom_reap_task(tsk); - WRITE_ONCE(task_to_reap, NULL); + (!list_empty(&oom_reaper_list))); + spin_lock(&oom_reaper_lock); + if (!list_empty(&oom_reaper_list)) { + tsk = list_first_entry(&oom_reaper_list, + struct task_struct, oom_reaper_list); + list_del(&tsk->oom_reaper_list); + } + spin_unlock(&oom_reaper_lock); + + if (tsk) + oom_reap_task(tsk); } return 0; @@ -536,23 +546,15 @@ static int oom_reaper(void *unused) static void wake_oom_reaper(struct task_struct *tsk) { - struct task_struct *old_tsk; - if (!oom_reaper_th) return; get_task_struct(tsk); - /* - * Make sure that only a single mm is ever queued for the reaper - * because multiple are not necessary and the operation might be - * disruptive so better reduce it to the bare minimum. - */ - old_tsk = cmpxchg(&task_to_reap, NULL, tsk); - if (!old_tsk) - wake_up(&oom_reaper_wait); - else - put_task_struct(tsk); + spin_lock(&oom_reaper_lock); + list_add(&tsk->oom_reaper_list, &oom_reaper_list); + spin_unlock(&oom_reaper_lock); + wake_up(&oom_reaper_wait); } static int __init oom_init(void) -- 2.7.0 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2016-03-22 11:03 UTC|newest] Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top 2016-03-22 11:00 [PATCH 0/9] oom reaper v6 Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` [PATCH 1/9] sched: add schedule_timeout_idle() Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 12:23 ` Peter Zijlstra 2016-03-22 12:23 ` Peter Zijlstra 2016-03-22 12:33 ` Michal Hocko 2016-03-22 12:33 ` Michal Hocko 2016-03-22 12:51 ` Peter Zijlstra 2016-03-22 12:51 ` Peter Zijlstra 2016-03-22 13:08 ` Michal Hocko 2016-03-22 13:08 ` Michal Hocko 2016-03-22 13:22 ` Peter Zijlstra 2016-03-22 13:22 ` Peter Zijlstra 2016-03-22 17:56 ` Johannes Weiner 2016-03-22 17:56 ` Johannes Weiner 2016-03-22 21:23 ` Peter Zijlstra 2016-03-22 21:23 ` Peter Zijlstra 2016-03-23 10:43 ` Michal Hocko 2016-03-23 10:43 ` Michal Hocko 2016-03-22 23:02 ` Andrew Morton 2016-03-22 23:02 ` Andrew Morton 2016-03-22 11:00 ` [PATCH 2/9] mm, oom: introduce oom reaper Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 22:45 ` Andrew Morton 2016-03-22 22:45 ` Andrew Morton 2016-03-22 22:58 ` Hugh Dickins 2016-03-22 22:58 ` Hugh Dickins 2016-03-22 11:00 ` [PATCH 3/9] oom: clear TIF_MEMDIE after oom_reaper managed to unmap the address space Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` [PATCH 4/9] mm, oom_reaper: report success/failure Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` Michal Hocko [this message] 2016-03-22 11:00 ` [PATCH 5/9] mm, oom_reaper: implement OOM victims queuing Michal Hocko 2016-03-22 11:00 ` [PATCH 6/9] oom, oom_reaper: disable oom_reaper for oom_kill_allocating_task Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` [PATCH 7/9] oom: make oom_reaper_list single linked Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` [PATCH 8/9] oom: make oom_reaper freezable Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 11:00 ` [PATCH 9/9] oom, oom_reaper: protect oom_reaper_list using simpler way Michal Hocko 2016-03-22 11:00 ` Michal Hocko 2016-03-22 22:08 ` [PATCH 0/9] oom reaper v6 David Rientjes 2016-03-22 22:08 ` David Rientjes 2016-03-23 11:11 ` Tetsuo Handa 2016-03-23 11:11 ` Tetsuo Handa 2016-03-23 12:07 ` Michal Hocko 2016-03-23 12:07 ` Michal Hocko
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1458644426-22973-6-git-send-email-mhocko@kernel.org \ --to=mhocko@kernel.org \ --cc=akpm@linux-foundation.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mm@kvack.org \ --cc=mhocko@suse.com \ --cc=penguin-kernel@I-love.SAKURA.ne.jp \ --cc=rientjes@google.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.