[Devel] [RFC 25/54] cgroup-v1: fix CONFIG_VE=n build

Eva Kurchatova eva.kurchatova at virtuozzo.com
Wed Apr 29 22:58:25 MSK 2026


Signed-off-by: Eva Kurchatova <eva.kurchatova at virtuozzo.com>
---
 kernel/cgroup/cgroup-v1.c | 100 +++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 6 deletions(-)

diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index e4ef76e4bde6..f8a117d02d0b 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -39,6 +39,11 @@ static bool cgroup_no_v1_named;
  */
 static struct workqueue_struct *cgroup_pidlist_destroy_wq;
 
+#ifndef CONFIG_VE
+/* protects cgroup_subsys->release_agent_path */
+static DEFINE_SPINLOCK(release_agent_path_lock);
+#endif
+
 bool cgroup1_ssid_disabled(int ssid)
 {
 	return cgroup_no_v1_mask & (1 << ssid);
@@ -548,10 +553,12 @@ static ssize_t cgroup1_tasks_write(struct kernfs_open_file *of,
 static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
 					  char *buf, size_t nbytes, loff_t off)
 {
-	struct cgroup *root_cgrp;
-	struct ve_struct *ve = NULL;
 	struct cgroup *cgrp;
 	struct cgroup_file_ctx *ctx;
+
+#ifdef CONFIG_VE
+	struct cgroup *root_cgrp;
+	struct ve_struct *ve = NULL;
 	int ret;
 
 	/*
@@ -599,13 +606,37 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
 	put_ve(ve);
 	cgroup_kn_unlock(of->kn);
 	return ret ? : nbytes;
+#else
+	BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+
+	/*
+	 * Release agent gets called with all capabilities,
+	 * require capabilities to set release agent.
+	 */
+	ctx = of->priv;
+	if ((ctx->ns->user_ns != &init_user_ns) ||
+		!file_ns_capable(of->file, &init_user_ns, CAP_SYS_ADMIN))
+		return -EPERM;
+
+	cgrp = cgroup_kn_lock_live(of->kn, false);
+	if (!cgrp)
+		return -ENODEV;
+	spin_lock(&release_agent_path_lock);
+	strscpy(cgrp->root->release_agent_path, strstrip(buf),
+		sizeof(cgrp->root->release_agent_path));
+	spin_unlock(&release_agent_path_lock);
+	cgroup_kn_unlock(of->kn);
+	return nbytes;
+#endif
 }
 
 static int cgroup_release_agent_show(struct seq_file *seq, void *v)
 {
+	struct cgroup *cgrp = seq_css(seq)->cgroup;
+
+#ifdef CONFIG_VE
 	const char *release_agent = NULL;
 	struct cgroup *root_cgrp;
-	struct cgroup *cgrp = seq_css(seq)->cgroup;
 	struct ve_struct *ve = NULL;
 
 	rcu_read_lock();
@@ -623,6 +654,12 @@ static int cgroup_release_agent_show(struct seq_file *seq, void *v)
 	if (release_agent)
 		seq_puts(seq, release_agent);
 	rcu_read_unlock();
+#else
+	spin_lock(&release_agent_path_lock);
+	seq_puts(seq, cgrp->root->release_agent_path);
+	spin_unlock(&release_agent_path_lock);
+	seq_putc(seq, '\n');
+#endif
 
 	seq_putc(seq, '\n');
 	return 0;
@@ -832,7 +869,11 @@ void cgroup1_check_for_release(struct cgroup *cgrp)
 {
 	if (notify_on_release(cgrp) && !cgroup_is_populated(cgrp) &&
 	    !css_has_online_children(&cgrp->self) && !cgroup_is_dead(cgrp))
+#ifdef CONFIG_VE
 		ve_add_to_release_list(cgrp);
+#else
+		schedule_work(&cgrp->release_agent_work);
+#endif
 }
 
 /*
@@ -860,6 +901,7 @@ void cgroup1_check_for_release(struct cgroup *cgrp)
  */
 void cgroup1_release_agent(struct work_struct *work)
 {
+#ifdef CONFIG_VE
 	struct ve_struct *ve =
 		container_of(work, struct ve_struct, release_agent_work);
 	/*
@@ -871,6 +913,10 @@ void cgroup1_release_agent(struct work_struct *work)
 	 */
 	struct cgroup_namespace *ve_cgroup_ns =
 		rcu_dereference_protected(ve->ve_nsproxy, 1)->cgroup_ns;
+#else
+	struct cgroup *cgrp =
+		container_of(work, struct cgroup, release_agent_work);
+#endif
 	char *pathbuf, *agentbuf;
 	char *argv[3], *envp[3];
 	unsigned long flags;
@@ -882,6 +928,7 @@ void cgroup1_release_agent(struct work_struct *work)
 	if (!pathbuf || !agentbuf)
 		goto out_free;
 
+#ifdef CONFIG_VE
 	spin_lock_irqsave(&ve->release_list_lock, flags);
 	while (!list_empty(&ve->release_list)) {
 		struct cgroup *cgrp;
@@ -939,6 +986,28 @@ void cgroup1_release_agent(struct work_struct *work)
 		spin_lock_irqsave(&ve->release_list_lock, flags);
 	}
 	spin_unlock_irqrestore(&ve->release_list_lock, flags);
+#else
+	spin_lock(&release_agent_path_lock);
+	strscpy(agentbuf, cgrp->root->release_agent_path, PATH_MAX);
+	spin_unlock(&release_agent_path_lock);
+	if (!agentbuf[0])
+		goto out_free;
+
+	ret = cgroup_path_ns(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns);
+	if (ret < 0)
+		goto out_free;
+
+	argv[0] = agentbuf;
+	argv[1] = pathbuf;
+	argv[2] = NULL;
+
+	/* minimal command environment */
+	envp[0] = "HOME=/";
+	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[2] = NULL;
+
+	call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
+#endif
 out_free:
 	kfree(agentbuf);
 	kfree(pathbuf);
@@ -985,10 +1054,12 @@ static int cgroup1_rename(struct kernfs_node *kn, struct kernfs_node *new_parent
 
 static int cgroup1_show_options(struct seq_file *seq, struct kernfs_root *kf_root)
 {
-	const char *release_agent;
 	struct cgroup_root *root = cgroup_root_from_kf(kf_root);
 	struct cgroup_subsys *ss;
 	int ssid;
+#ifdef CONFIG_VE
+	const char *release_agent;
+#endif
 
 	for_each_subsys(ss, ssid)
 		if (root->subsys_mask & (1 << ssid))
@@ -1002,11 +1073,20 @@ static int cgroup1_show_options(struct seq_file *seq, struct kernfs_root *kf_roo
 	if (root->flags & CGRP_ROOT_FAVOR_DYNMODS)
 		seq_puts(seq, ",favordynmods");
 
+#ifdef CONFIG_VE
 	rcu_read_lock();
 	release_agent = ve_ra_data_get_path_locked(get_exec_env(), root);
 	if (release_agent && release_agent[0])
 		seq_show_option(seq, "release_agent", release_agent);
 	rcu_read_unlock();
+#else
+	spin_lock(&release_agent_path_lock);
+	if (strlen(root->release_agent_path))
+		seq_show_option(seq, "release_agent",
+				root->release_agent_path);
+	spin_unlock(&release_agent_path_lock);
+#endif
+
 	if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
 		seq_puts(seq, ",clone_children");
 	if (strlen(root->name))
@@ -1238,8 +1318,16 @@ int cgroup1_reconfigure(struct fs_context *fc)
 
 	WARN_ON(rebind_subsystems(&cgrp_dfl_root, removed_mask));
 
+#ifdef CONFIG_VE
 	if (ctx->release_agent)
 		ret = ve_ra_data_set(get_exec_env(), root, ctx->release_agent);
+#else
+	if (ctx->release_agent) {
+		spin_lock(&release_agent_path_lock);
+		strcpy(root->release_agent_path, ctx->release_agent);
+		spin_unlock(&release_agent_path_lock);
+	}
+#endif
 
 	trace_cgroup_remount(root);
 
@@ -1372,10 +1460,10 @@ int cgroup1_get_tree(struct fs_context *fc)
 		ret = 1;	/* restart */
 
 	cgroup_unlock();
-
+#ifdef CONFIG_VE
 	if (!ret && ve_hide_cgroups(ctx->root))
 		ret = -EPERM;
-
+#endif
 	if (!ret)
 		ret = cgroup_do_get_tree(fc);
 
-- 
2.54.0



More information about the Devel mailing list