Skip to content

Commit

Permalink
mm: memcontrol: fix NUMA round-robin reclaim at intermediate level
Browse files Browse the repository at this point in the history
When a cgroup is reclaimed on behalf of a configured limit, reclaim
needs to round-robin through all NUMA nodes that hold pages of the memcg
in question.  However, when assembling the mask of candidate NUMA nodes,
the code only consults the *local* cgroup LRU counters, not the
recursive counters for the entire subtree.  Cgroup limits are frequently
configured against intermediate cgroups that do not have memory on their
own LRUs.  In this case, the node mask will always come up empty and
reclaim falls back to scanning only the current node.

If a cgroup subtree has some memory on one node but the processes are
bound to another node afterwards, the limit reclaim will never age or
reclaim that memory anymore.

To fix this, use the recursive LRU counts for a cgroup subtree to
determine which nodes hold memory of that cgroup.

The code has been broken like this forever, so it doesn't seem to be a
problem in practice.  I just noticed it while reviewing the way the LRU
counters are used in general.

Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Johannes Weiner <[email protected]>
Reviewed-by: Shakeel Butt <[email protected]>
Reviewed-by: Roman Gushchin <[email protected]>
Cc: Michal Hocko <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
hnaz authored and torvalds committed May 15, 2019
1 parent 42a3003 commit def0fda
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions mm/memcontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1507,13 +1507,13 @@ static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *memcg,
{
struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);

if (lruvec_page_state_local(lruvec, NR_INACTIVE_FILE) ||
lruvec_page_state_local(lruvec, NR_ACTIVE_FILE))
if (lruvec_page_state(lruvec, NR_INACTIVE_FILE) ||
lruvec_page_state(lruvec, NR_ACTIVE_FILE))
return true;
if (noswap || !total_swap_pages)
return false;
if (lruvec_page_state_local(lruvec, NR_INACTIVE_ANON) ||
lruvec_page_state_local(lruvec, NR_ACTIVE_ANON))
if (lruvec_page_state(lruvec, NR_INACTIVE_ANON) ||
lruvec_page_state(lruvec, NR_ACTIVE_ANON))
return true;
return false;

Expand Down

0 comments on commit def0fda

Please sign in to comment.