summaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 0e3a8c11fb3b..07032c088608 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -6264,13 +6264,27 @@ struct cgroup_subsys memory_cgrp_subsys = {
* budget is NOT proportional. A cgroup's protection from a sibling
* is capped to its own memory.min/low setting.
*
+ * 5. However, to allow protecting recursive subtrees from each other
+ * without having to declare each individual cgroup's fixed share
+ * of the ancestor's claim to protection, any unutilized -
+ * "floating" - protection from up the tree is distributed in
+ * proportion to each cgroup's *usage*. This makes the protection
+ * neutral wrt sibling cgroups and lets them compete freely over
+ * the shared parental protection budget, but it protects the
+ * subtree as a whole from neighboring subtrees.
+ *
+ * Note that 4. and 5. are not in conflict: 4. is about protecting
+ * against immediate siblings whereas 5. is about protecting against
+ * neighboring subtrees.
*/
static unsigned long effective_protection(unsigned long usage,
+ unsigned long parent_usage,
unsigned long setting,
unsigned long parent_effective,
unsigned long siblings_protected)
{
unsigned long protected;
+ unsigned long ep;
protected = min(usage, setting);
/*
@@ -6301,7 +6315,34 @@ static unsigned long effective_protection(unsigned long usage,
* protection is always dependent on how memory is actually
* consumed among the siblings anyway.
*/
- return protected;
+ ep = protected;
+
+ /*
+ * If the children aren't claiming (all of) the protection
+ * afforded to them by the parent, distribute the remainder in
+ * proportion to the (unprotected) memory of each cgroup. That
+ * way, cgroups that aren't explicitly prioritized wrt each
+ * other compete freely over the allowance, but they are
+ * collectively protected from neighboring trees.
+ *
+ * We're using unprotected memory for the weight so that if
+ * some cgroups DO claim explicit protection, we don't protect
+ * the same bytes twice.
+ */
+ if (!(cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_RECURSIVE_PROT))
+ return ep;
+
+ if (parent_effective > siblings_protected && usage > protected) {
+ unsigned long unclaimed;
+
+ unclaimed = parent_effective - siblings_protected;
+ unclaimed *= usage - protected;
+ unclaimed /= parent_usage - siblings_protected;
+
+ ep += unclaimed;
+ }
+
+ return ep;
}
/**
@@ -6321,8 +6362,8 @@ static unsigned long effective_protection(unsigned long usage,
enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
struct mem_cgroup *memcg)
{
+ unsigned long usage, parent_usage;
struct mem_cgroup *parent;
- unsigned long usage;
if (mem_cgroup_disabled())
return MEMCG_PROT_NONE;
@@ -6347,11 +6388,13 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
goto out;
}
- memcg->memory.emin = effective_protection(usage,
+ parent_usage = page_counter_read(&parent->memory);
+
+ memcg->memory.emin = effective_protection(usage, parent_usage,
memcg->memory.min, READ_ONCE(parent->memory.emin),
atomic_long_read(&parent->memory.children_min_usage));
- memcg->memory.elow = effective_protection(usage,
+ memcg->memory.elow = effective_protection(usage, parent_usage,
memcg->memory.low, READ_ONCE(parent->memory.elow),
atomic_long_read(&parent->memory.children_low_usage));