[Devel] [PATCH rh7 2/2] cgroups: Introduce subgroups_limit control

Andrey Ryabinin aryabinin at virtuozzo.com
Wed Jan 18 04:46:29 PST 2017


Having a lot memory cgroups on machine may cause significant slowdown.
So we want to limit number of sub-groups that container can create.
This patch adds cgroup.subgroups_limit control file for that purpose.
The file is present only on container's root cgroup.

https://jira.sw.ru/browse/PSBM-33401
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 include/linux/cgroup.h |  1 +
 kernel/cgroup.c        | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 816cbac..d99251b 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -284,6 +284,7 @@ struct cgroup {
 
 	/* directory xattrs */
 	struct simple_xattrs xattrs;
+	u64 subgroups_limit;
 };
 
 #define MAX_CGROUP_ROOT_NAMELEN 64
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 9a39c26..3e2de0b4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4040,6 +4040,19 @@ static int cgroup_clone_children_write(struct cgroup *cgrp,
 	return 0;
 }
 
+static u64 cgroup_read_subgroups_limit(struct cgroup *cgrp,
+				struct cftype *cft)
+{
+	return cgrp->subgroups_limit;
+}
+static int cgroup_write_subgroups_limit(struct cgroup *cgrp,
+					struct cftype *cft,
+					u64 val)
+{
+	cgrp->subgroups_limit = val;
+	return 0;
+}
+
 /*
  * for the common functions, 'private' gives the type of file
  */
@@ -4090,6 +4103,13 @@ static struct cftype files[] = {
 		.write_string = cgroup_release_agent_write,
 		.max_write_len = PATH_MAX,
 	},
+	{
+		.name = "cgroup.subgroups_limit",
+		.flags = CFTYPE_ONLY_ON_VE_ROOT,
+		.read_u64 = cgroup_read_subgroups_limit,
+		.write_u64 = cgroup_write_subgroups_limit,
+		.mode = S_IRUGO | S_IWUSR,
+	},
 	{ }	/* terminate */
 };
 
@@ -4205,6 +4225,19 @@ static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
 	cgrp->subsys[ss->subsys_id]->flags &= ~CSS_ONLINE;
 }
 
+static int subgroups_count(struct cgroup *cgroup)
+{
+	struct cgroup *pos;
+	int cgrps_count = 0;
+
+	rcu_read_lock();
+	cgroup_for_each_descendant_post(pos, cgroup)
+		cgrps_count++;
+	rcu_read_unlock();
+
+	return cgrps_count;
+}
+
 #ifdef CONFIG_VE
 static void cgroup_add_ve_root_files(struct cgroup *cgrp,
 				struct cgroup_subsys *subsys,
@@ -4244,6 +4277,27 @@ void cgroup_mark_ve_root(struct ve_struct *ve)
 	mutex_unlock(&cgroup_mutex);
 }
 
+static struct cgroup *cgroup_get_ve_root(struct cgroup *cgrp)
+{
+	struct cgroup *ve_root = NULL;
+
+	rcu_read_lock();
+	do {
+		if (test_bit(CGRP_VE_ROOT, &cgrp->flags)) {
+			ve_root = cgrp;
+			break;
+		}
+		cgrp = cgrp->parent;
+	} while (cgrp);
+	rcu_read_unlock();
+
+	return ve_root;
+}
+#else
+static inline struct cgroup *cgroup_get_ve_root(struct cgroup *cgrp)
+{
+	return NULL;
+}
 #endif
 
 /*
@@ -4263,6 +4317,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 	int err = 0;
 	struct cgroup_subsys *ss;
 	struct super_block *sb = root->sb;
+	struct cgroup *ve_root = parent;
 
 	/* allocate the cgroup and its ID, 0 is reserved for the root */
 	cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
@@ -4278,6 +4333,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 	if (cgrp->id < 0)
 		goto err_free_name;
 
+	ve_root = cgroup_get_ve_root(parent);
+	if (ve_root && ve_root->subgroups_limit > 0 &&
+			subgroups_count(ve_root) >= ve_root->subgroups_limit) {
+		err = -EACCES;
+		goto err_free_name;
+	}
+
 	/*
 	 * Only live parents can have children.  Note that the liveliness
 	 * check isn't strictly necessary because cgroup_mkdir() and
-- 
2.10.2



More information about the Devel mailing list