aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2018-10-26 18:03:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-26 19:25:19 -0400
commit15f570bf3d13aa94a97234538a5110d18df03aa3 (patch)
treeb0d42d4904ed7a8309eb357b0bf0441cccc59993 /mm/page_alloc.c
parent68600f623d69da428c6163275f97ca126e1a8ec5 (diff)
mm,page_alloc: PF_WQ_WORKER threads must sleep at should_reclaim_retry()
Tetsuo Handa has reported that it is possible to bypass the short sleep for PF_WQ_WORKER threads which was introduced by commit 373ccbe5927034b5 ("mm, vmstat: allow WQ concurrency to discover memory reclaim doesn't make any progress") and lock up the system if OOM. The primary reason is that WQ_MEM_RECLAIM WQs are not guaranteed to run even when they have a rescuer available. Those workers might be essential for reclaim to make a forward progress, however. If we are too unlucky all the allocations requests can get stuck waiting for a WQ_MEM_RECLAIM work item and the system is essentially stuck in an OOM condition without much hope to move on. Tetsuo has seen the reclaim stuck on drain_local_pages_wq or xlog_cil_push_work (xfs). There might be others. Since should_reclaim_retry() should be a natural reschedule point, let's do the short sleep for PF_WQ_WORKER threads unconditionally in order to guarantee that other pending work items are started. This will workaround this problem and it is less fragile than hunting down when the sleep is missed. Having a single sleeping point is more robust. [akpm@linux-foundation.org: reflow comment to 80 cols to save a couple of lines] Link: http://lkml.kernel.org/r/20180827135101.15700-1-mhocko@kernel.org Signed-off-by: Michal Hocko <mhocko@suse.com> Debugged-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Cc: Roman Gushchin <guro@fb.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Vladimir Davydov <vdavydov.dev@gmail.com> Cc: David Rientjes <rientjes@google.com> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e2ef1c17942f..7e2fb6e38f34 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3922,6 +3922,7 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
3922{ 3922{
3923 struct zone *zone; 3923 struct zone *zone;
3924 struct zoneref *z; 3924 struct zoneref *z;
3925 bool ret = false;
3925 3926
3926 /* 3927 /*
3927 * Costly allocations might have made a progress but this doesn't mean 3928 * Costly allocations might have made a progress but this doesn't mean
@@ -3985,25 +3986,24 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
3985 } 3986 }
3986 } 3987 }
3987 3988
3988 /* 3989 ret = true;
3989 * Memory allocation/reclaim might be called from a WQ 3990 goto out;
3990 * context and the current implementation of the WQ
3991 * concurrency control doesn't recognize that
3992 * a particular WQ is congested if the worker thread is
3993 * looping without ever sleeping. Therefore we have to
3994 * do a short sleep here rather than calling
3995 * cond_resched().
3996 */
3997 if (current->flags & PF_WQ_WORKER)
3998 schedule_timeout_uninterruptible(1);
3999 else
4000 cond_resched();
4001
4002 return true;
4003 } 3991 }
4004 } 3992 }
4005 3993
4006 return false; 3994out:
3995 /*
3996 * Memory allocation/reclaim might be called from a WQ context and the
3997 * current implementation of the WQ concurrency control doesn't
3998 * recognize that a particular WQ is congested if the worker thread is
3999 * looping without ever sleeping. Therefore we have to do a short sleep
4000 * here rather than calling cond_resched().
4001 */
4002 if (current->flags & PF_WQ_WORKER)
4003 schedule_timeout_uninterruptible(1);
4004 else
4005 cond_resched();
4006 return ret;
4007} 4007}
4008 4008
4009static inline bool 4009static inline bool