• Yafang Shao's avatar
    mm, memcg: avoid stale protection values when cgroup is above protection · 22f7496f
    Yafang Shao authored
    Patch series "mm, memcg: memory.{low,min} reclaim fix & cleanup", v4.
    
    This series contains a fix for a edge case in my earlier protection
    calculation patches, and a patch to make the area overall a little more
    robust to hopefully help avoid this in future.
    
    This patch (of 2):
    
    A cgroup can have both memory protection and a memory limit to isolate it
    from its siblings in both directions - for example, to prevent it from
    being shrunk below 2G under high pressure from outside, but also from
    growing beyond 4G under low pressure.
    
    Commit 9783aa99 ("mm, memcg: proportional memory.{low,min} reclaim")
    implemented proportional scan pressure so that multiple siblings in excess
    of their protection settings don't get reclaimed equally but instead in
    accordance to their unprotected portion.
    
    During limit reclaim, this proportionality shouldn't apply of course:
    there is no competition, all pressure is from within the cgroup and should
    be applied as such.  Reclaim should operate at full efficiency.
    
    However, mem_cgroup_protected() never expected anybody to look at the
    effective protection values when it indicated that the cgroup is above its
    protection.  As a result, a query during limit reclaim may return stale
    protection values that were calculated by a previous reclaim cycle in
    which the cgroup did have siblings.
    
    When this happens, reclaim is unnecessarily hesitant and potentially slow
    to meet the desired limit.  In theory this could lead to premature OOM
    kills, although it's not obvious this has occurred in practice.
    
    Workaround the problem by special casing reclaim roots in
    mem_cgroup_protection.  These memcgs are never participating in the
    reclaim protection because the reclaim is internal.
    
    We have to ignore effective protection values for reclaim roots because
    mem_cgroup_protected might be called from racing reclaim contexts with
    different roots.  Calculation is relying on root -> leaf tree traversal
    therefore top-down reclaim protection invariants should hold.  The only
    exception is the reclaim root which should have effective protection set
    to 0 but that would be problematic for the following setup:
    
     Let's have global and A's reclaim in parallel:
      |
      A (low=2G, usage = 3G, max = 3G, children_low_usage = 1.5G)
      |\
      | C (low = 1G, usage = 2.5G)
      B (low = 1G, usage = 0.5G)
    
     for A reclaim we have
     B.elow = B.low
     C.elow = C.low
    
     For the global reclaim
     A.elow = A.low
     B.elow = min(B.usage, B.low) because children_low_usage <= A.elow
     C.elow = min(C.usage, C.low)
    
     With the effective values resetting we have A reclaim
     A.elow = 0
     B.elow = B.low
     C.elow = C.low
    
     and global reclaim could see the above and then
     B.elow = C.elow = 0 because children_low_usage > A.elow
    
    Which means that protected memcgs would get reclaimed.
    
    In future we would like to make mem_cgroup_protected more robust against
    racing reclaim contexts but that is likely more complex solution than this
    simple workaround.
    
    [hannes@cmpxchg.org - large part of the changelog]
    [mhocko@suse.com - workaround explanation]
    [chris@chrisdown.name - retitle]
    
    Fixes: 9783aa99 ("mm, memcg: proportional memory.{low,min} reclaim")
    Signed-off-by: default avatarYafang Shao <laoar.shao@gmail.com>
    Signed-off-by: default avatarChris Down <chris@chrisdown.name>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Acked-by: default avatarMichal Hocko <mhocko@suse.com>
    Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
    Acked-by: default avatarChris Down <chris@chrisdown.name>
    Acked-by: default avatarRoman Gushchin <guro@fb.com>
    Link: http://lkml.kernel.org/r/cover.1594638158.git.chris@chrisdown.name
    Link: http://lkml.kernel.org/r/044fb8ecffd001c7905d27c0c2ad998069fdc396.1594638158.git.chris@chrisdown.nameSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    22f7496f
vmscan.c 123 KB