Commit 15f570bf authored by Michal Hocko's avatar Michal Hocko Committed by Linus Torvalds

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 373ccbe5
("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.orgSigned-off-by: default avatarMichal Hocko <mhocko@suse.com>
Debugged-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reported-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: default avatarAndrew 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 68600f62
...@@ -3922,6 +3922,7 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order, ...@@ -3922,6 +3922,7 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
{ {
struct zone *zone; struct zone *zone;
struct zoneref *z; struct zoneref *z;
bool ret = false;
/* /*
* Costly allocations might have made a progress but this doesn't mean * 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,25 +3986,24 @@ should_reclaim_retry(gfp_t gfp_mask, unsigned order,
} }
} }
ret = true;
goto out;
}
}
out:
/* /*
* Memory allocation/reclaim might be called from a WQ * Memory allocation/reclaim might be called from a WQ context and the
* context and the current implementation of the WQ * current implementation of the WQ concurrency control doesn't
* concurrency control doesn't recognize that * recognize that a particular WQ is congested if the worker thread is
* a particular WQ is congested if the worker thread is * looping without ever sleeping. Therefore we have to do a short sleep
* looping without ever sleeping. Therefore we have to * here rather than calling cond_resched().
* do a short sleep here rather than calling
* cond_resched().
*/ */
if (current->flags & PF_WQ_WORKER) if (current->flags & PF_WQ_WORKER)
schedule_timeout_uninterruptible(1); schedule_timeout_uninterruptible(1);
else else
cond_resched(); cond_resched();
return ret;
return true;
}
}
return false;
} }
static inline bool static inline bool
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment