Thread (25 messages) 25 messages, 5 authors, 2020-05-04

Re: [PATCH 1/2] mm, memcg: Avoid stale protection values when cgroup is above protection

From: Yafang Shao <hidden>
Date: 2020-05-01 00:00:37
Also in: linux-mm, lkml

On Thu, Apr 30, 2020 at 10:57 PM Michal Hocko [off-list ref] wrote:
On Wed 29-04-20 12:56:27, Johannes Weiner wrote:
[...]
quoted
I think to address this, we need a more comprehensive solution and
introduce some form of serialization. I'm not sure yet how that would
look like yet.
Yeah, that is what I've tried to express earlier and that is why I would
rather go with an uglier workaround for now and think about a more
robust effective values calculation on top.
Agreed.
If there's a more robust effective values calculation on top, then we
don't need to hack it here and there.
quoted
I'm still not sure it's worth having a somewhat ugly workaround in
mem_cgroup_protection() to protect against half of the bug. If you
think so, the full problem should at least be documented and marked
XXX or something.
Yes, this makes sense to me. What about the following?
Many thanks for the explaination on this workaround.
With this explanation, I think the others will have a clear idea why
we must add this ugly workaround here.

quoted hunk ↗ jump to hunk
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 1b4150ff64be..50ffbc17cdd8 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -350,6 +350,42 @@ static inline unsigned long mem_cgroup_protection(struct mem_cgroup *memcg,
        if (mem_cgroup_disabled())
                return 0;

+       /*
+        * There is no reclaim protection applied to a targeted reclaim.
+        * We are special casing this specific case here because
+        * mem_cgroup_protected calculation is not robust enough to keep
+        * the protection invariant for calculated effective values for
+        * parallel reclaimers with different reclaim target. This is
+        * especially a problem for tail memcgs (as they have pages on LRU)
+        * which would want to have effective values 0 for targeted reclaim
+        * but a different value for external reclaim.
+        *
+        * Example
+        * 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 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
+        *
+        * If the global reclaim races with A's reclaim then
+        * B.elow = C.elow = 0 because children_low_usage > A.elow)
+        * is possible and reclaiming B would be violating the protection.
+        *
+        */
+       if (memcg == root)
+               return 0;
+
        if (in_low_reclaim)
                return READ_ONCE(memcg->memory.emin);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 05b4ec2c6499..df88a22f09bc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -6385,6 +6385,14 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,

        if (!root)
                root = root_mem_cgroup;
+
+       /*
+        * Effective values of the reclaim targets are ignored so they
+        * can be stale. Have a look at mem_cgroup_protection for more
+        * details.
+        * TODO: calculation should be more robust so that we do not need
+        * that special casing.
+        */
        if (memcg == root)
                return MEMCG_PROT_NONE;

quoted
In practice, I doubt this matters all that much because limit reclaim
and global reclaim tend to occur in complementary
containerization/isolation strategies, not heavily simultaneously.
I would expect that as well but this is always hard to tell.

--
Michal Hocko
SUSE Labs


-- 
Thanks
Yafang
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help