|
@@ -1782,6 +1782,34 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
|
|
|
+ unsigned long long *mem_limit, unsigned long long *memsw_limit)
|
|
|
+{
|
|
|
+ struct cgroup *cgroup;
|
|
|
+ unsigned long long min_limit, min_memsw_limit, tmp;
|
|
|
+
|
|
|
+ min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT);
|
|
|
+ min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
|
|
|
+ cgroup = memcg->css.cgroup;
|
|
|
+ if (!memcg->use_hierarchy)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ while (cgroup->parent) {
|
|
|
+ cgroup = cgroup->parent;
|
|
|
+ memcg = mem_cgroup_from_cont(cgroup);
|
|
|
+ if (!memcg->use_hierarchy)
|
|
|
+ break;
|
|
|
+ tmp = res_counter_read_u64(&memcg->res, RES_LIMIT);
|
|
|
+ min_limit = min(min_limit, tmp);
|
|
|
+ tmp = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
|
|
|
+ min_memsw_limit = min(min_memsw_limit, tmp);
|
|
|
+ }
|
|
|
+out:
|
|
|
+ *mem_limit = min_limit;
|
|
|
+ *memsw_limit = min_memsw_limit;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
|
|
|
{
|
|
|
struct mem_cgroup *mem;
|
|
@@ -1855,6 +1883,13 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
|
|
|
cb->fill(cb, "unevictable", unevictable * PAGE_SIZE);
|
|
|
|
|
|
}
|
|
|
+ {
|
|
|
+ unsigned long long limit, memsw_limit;
|
|
|
+ memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit);
|
|
|
+ cb->fill(cb, "hierarchical_memory_limit", limit);
|
|
|
+ if (do_swap_account)
|
|
|
+ cb->fill(cb, "hierarchical_memsw_limit", memsw_limit);
|
|
|
+ }
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_VM
|
|
|
cb->fill(cb, "inactive_ratio", calc_inactive_ratio(mem_cont, NULL));
|