]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/memcontrol.c
memcg: memory cgroup hierarchy feature selector
[net-next-2.6.git] / mm / memcontrol.c
index 20e1d90b3363a6e59191e48fe1660af166732723..886e2224c5fdde439cb99da510159065e545b796 100644 (file)
@@ -149,6 +149,10 @@ struct mem_cgroup {
         * reclaimed from. Protected by cgroup_lock()
         */
        struct mem_cgroup *last_scanned_child;
+       /*
+        * Should the accounting and control be hierarchical, per subtree?
+        */
+       bool use_hierarchy;
 
        int             obsolete;
        atomic_t        refcnt;
@@ -1543,6 +1547,44 @@ int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event)
 }
 
 
+static u64 mem_cgroup_hierarchy_read(struct cgroup *cont, struct cftype *cft)
+{
+       return mem_cgroup_from_cont(cont)->use_hierarchy;
+}
+
+static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
+                                       u64 val)
+{
+       int retval = 0;
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
+       struct cgroup *parent = cont->parent;
+       struct mem_cgroup *parent_mem = NULL;
+
+       if (parent)
+               parent_mem = mem_cgroup_from_cont(parent);
+
+       cgroup_lock();
+       /*
+        * If parent's use_hiearchy is set, we can't make any modifications
+        * in the child subtrees. If it is unset, then the change can
+        * occur, provided the current cgroup has no children.
+        *
+        * For the root cgroup, parent_mem is NULL, we allow value to be
+        * set if there are no children.
+        */
+       if ((!parent_mem || !parent_mem->use_hierarchy) &&
+                               (val == 1 || val == 0)) {
+               if (list_empty(&cont->children))
+                       mem->use_hierarchy = val;
+               else
+                       retval = -EBUSY;
+       } else
+               retval = -EINVAL;
+       cgroup_unlock();
+
+       return retval;
+}
+
 static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
 {
        struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
@@ -1706,6 +1748,11 @@ static struct cftype mem_cgroup_files[] = {
                .name = "force_empty",
                .trigger = mem_cgroup_force_empty_write,
        },
+       {
+               .name = "use_hierarchy",
+               .write_u64 = mem_cgroup_hierarchy_write,
+               .read_u64 = mem_cgroup_hierarchy_read,
+       },
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -1881,12 +1928,18 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        if (cont->parent == NULL) {
                enable_swap_cgroup();
                parent = NULL;
-       } else
+       } else {
                parent = mem_cgroup_from_cont(cont->parent);
+               mem->use_hierarchy = parent->use_hierarchy;
+       }
 
-       res_counter_init(&mem->res, parent ? &parent->res : NULL);
-       res_counter_init(&mem->memsw, parent ? &parent->memsw : NULL);
-
+       if (parent && parent->use_hierarchy) {
+               res_counter_init(&mem->res, &parent->res);
+               res_counter_init(&mem->memsw, &parent->memsw);
+       } else {
+               res_counter_init(&mem->res, NULL);
+               res_counter_init(&mem->memsw, NULL);
+       }
 
        mem->last_scanned_child = NULL;