[Devel] [RFC][PATCH 1/1]a new optional function for task assignment to cgroup

Kazunaga Ikeno k-ikeno at ak.jp.nec.com
Tue Mar 4 21:41:38 PST 2008


From: Kazunaga Ikeno <k-ikeno at ak.jp.nec.com>

This patch provides the function leads a task, corresponding to specified user-id,
to a specific cgroup directory.


Signed-off-by: Kazunaga Ikeno <k-ikeno at ak.jp.nec.com>

Index: linux-2.6.25-rc3-mm1/kernel/sys.c
================================================================================
--- linux-2.6.25-rc3-mm1.orig/kernel/sys.c	2008-03-04 21:43:11.000000000 +0900
+++ linux-2.6.25-rc3-mm1/kernel/sys.c	2008-03-04 21:55:34.000000000 +0900
@@ -33,6 +33,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
+#include <linux/cgroup.h>

 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -644,6 +645,10 @@ asmlinkage long sys_setreuid(uid_t ruid,
 	key_fsuid_changed(current);
 	proc_id_connector(current, PROC_EVENT_UID);

+	retval = cgroup_attach_by_uid(current);
+	if (retval)
+		return retval;
+
 	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
 }

@@ -691,6 +696,10 @@ asmlinkage long sys_setuid(uid_t uid)
 	key_fsuid_changed(current);
 	proc_id_connector(current, PROC_EVENT_UID);

+	retval = cgroup_attach_by_uid(current);
+	if (retval)
+		return retval;
+
 	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
 }

@@ -739,6 +748,10 @@ asmlinkage long sys_setresuid(uid_t ruid
 	key_fsuid_changed(current);
 	proc_id_connector(current, PROC_EVENT_UID);

+	retval = cgroup_attach_by_uid(current);
+	if (retval)
+		return retval;
+
 	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
 }


Index: linux-2.6.25-rc3-mm1/include/linux/cgroup.h
================================================================================
--- linux-2.6.25-rc3-mm1.orig/include/linux/cgroup.h	2008-03-04 21:43:10.000000000 +0900
+++ linux-2.6.25-rc3-mm1/include/linux/cgroup.h	2008-03-04 21:57:32.000000000 +0900
@@ -30,6 +30,7 @@ extern void cgroup_unlock(void);
 extern void cgroup_fork(struct task_struct *p);
 extern void cgroup_fork_callbacks(struct task_struct *p);
 extern void cgroup_post_fork(struct task_struct *p);
+extern int cgroup_attach_by_uid(struct task_struct *p);
 extern void cgroup_exit(struct task_struct *p, int run_callbacks);
 extern int cgroupstats_build(struct cgroupstats *stats,
 				struct dentry *dentry);
@@ -356,6 +357,7 @@ static inline void cgroup_init_smp(void)
 static inline void cgroup_fork(struct task_struct *p) {}
 static inline void cgroup_fork_callbacks(struct task_struct *p) {}
 static inline void cgroup_post_fork(struct task_struct *p) {}
+static inline int cgroup_attach_by_uid(struct task_struct *p) {}
 static inline void cgroup_exit(struct task_struct *p, int callbacks) {}

 static inline void cgroup_lock(void) {}

Index: linux-2.6.25-rc3-mm1/kernel/cgroup.c
================================================================================
--- linux-2.6.25-rc3-mm1.orig/kernel/cgroup.c	2008-03-04 21:43:11.000000000 +0900
+++ linux-2.6.25-rc3-mm1/kernel/cgroup.c	2008-03-04 22:02:42.000000000 +0900
@@ -94,6 +94,9 @@ struct cgroupfs_root {
 	 * notification. We ensure that it's always a valid
 	 * NUL-terminated string */
 	char release_agent_path[PATH_MAX];
+
+	/* A list for the option that leads a task to cgroup */
+	struct list_head leadopt_list;
 };


@@ -177,6 +180,15 @@ struct cg_cgroup_link {
 	struct css_set *cg;
 };

+/* Link structure for the option that leads a task to cgroup */
+struct leadopt_entry {
+	struct list_head leadopt_link;
+	/* user-id of task to lead */
+	uid_t uid;
+	/* pathname of a cgroup directory */
+	char *pathname;
+};
+
 /* The default css_set - used by init and its children prior to any
  * hierarchies being mounted. It contains a pointer to the root state
  * for each subsystem. Also used to anchor the list of css_sets. Not
@@ -854,6 +866,7 @@ static void init_cgroup_root(struct cgro
 	struct cgroup *cgrp = &root->top_cgroup;
 	INIT_LIST_HEAD(&root->subsys_list);
 	INIT_LIST_HEAD(&root->root_list);
+	INIT_LIST_HEAD(&root->leadopt_list);
 	root->number_of_cgroups = 1;
 	cgrp->root = root;
 	cgrp->top_cgroup = cgrp;
@@ -1282,6 +1295,166 @@ static int attach_task_by_pid(struct cgr
 	return ret;
 }

+/*
+ * Lead a task, corresponding to specified user-id, to a specific
+ * cgroup directory.
+ */
+int cgroup_attach_by_uid(struct task_struct *tsk)
+{
+	struct cgroupfs_root *root;
+	struct list_head *l;
+	struct nameidata nd;
+	int ret = 0;
+	char *cgpath;
+
+	mutex_lock(&cgroup_mutex);
+	for_each_root(root) {
+		/* Skip this hierarchy if it has no active subsystems */
+		if (!root->actual_subsys_bits)
+			continue;
+		cgpath = 0;
+		l = root->leadopt_list.next;
+		while (l != &root->leadopt_list) {
+			struct leadopt_entry *link =
+				list_entry(l,
+					struct leadopt_entry, leadopt_link);
+			if (tsk->suid == link->uid)
+				cgpath = link->pathname;
+			else if (!cgpath && (tsk->euid == link->uid))
+				cgpath = link->pathname;
+			l = l->next;
+		}
+		if (cgpath) {
+			ret = path_lookup(cgpath, LOOKUP_DIRECTORY, &nd);
+			if (ret)
+				goto err0;
+			if (nd.path.dentry->d_fsdata == NULL) {
+				ret = -EPERM;
+				goto err1;
+			}
+			ret = cgroup_attach_task(
+				(struct cgroup *)(nd.path.dentry->d_fsdata),
+									tsk);
+			if (ret)
+				goto err1;
+			path_put(&nd.path);
+		}
+	}
+err0:
+	mutex_unlock(&cgroup_mutex);
+	return ret;
+
+err1:
+	path_put(&nd.path);
+	mutex_unlock(&cgroup_mutex);
+	return ret;
+}
+
+static int cgroup_leadopt_file_write(struct cgroupfs_root *root, char *buffer)
+{
+	struct leadopt_entry *link;
+	struct list_head *l;
+	int ret = 1;
+	int erase = 1;
+	char *options, *value, *dirto = NULL;
+	uid_t uid;
+
+	/* parse a command line */
+	while ((options = strsep(&buffer, " ,:")) != NULL) {
+		if (*options == (char)NULL) {
+			continue;
+		} else if (strcmp(options, "uid") == 0) {
+			while ((value = strsep(&buffer, " ,:")) != NULL) {
+				if (*value == (char)NULL)
+					continue;
+				if (sscanf(value, "%d", &uid) != 1)
+					return -EIO;
+				break;
+			}
+		} else if (strcmp(options, "leadto") == 0) {
+			while ((dirto = strsep(&buffer, " ,:")) != NULL) {
+				if (*dirto == (char)NULL)
+					continue;
+				erase = 0;
+				break;
+			}
+		}
+	}
+
+	/* Update a list for the option that leads a task to cgroup */
+	l = root->leadopt_list.next;
+	while (l != &root->leadopt_list) {
+		link = list_entry(l, struct leadopt_entry, leadopt_link);
+		if (link->uid == uid) {
+			list_del(&link->leadopt_link);
+			kfree(link->pathname);
+			kfree(link);
+			if (!erase) {
+				link = kmalloc(sizeof(*link), GFP_KERNEL);
+				if (link == NULL) {
+					ret = -ENOMEM;
+					goto err0;
+				}
+				link->uid = uid;
+				/* +1 for nul-terminator */
+				link->pathname = kmalloc((strlen(dirto)+1),
+								GFP_KERNEL);
+				strcpy(link->pathname, dirto);
+				list_add(&link->leadopt_link,
+							&root->leadopt_list);
+			}
+			break;
+		}
+		l = l->next;
+	}
+	if (!erase && (l == &root->leadopt_list)) {
+		link = kmalloc(sizeof(*link), GFP_KERNEL);
+		if (link == NULL) {
+			ret = -ENOMEM;
+			goto err0;
+		}
+		link->uid = uid;
+		/* +1 for nul-terminator */
+		link->pathname = kmalloc((strlen(dirto)+1), GFP_KERNEL);
+		strcpy(link->pathname, dirto);
+		list_add(&link->leadopt_link, &root->leadopt_list);
+	}
+
+err0:
+	return ret;
+}
+
+static ssize_t cgroup_leadopt_read(struct cgroup *cgrp,
+				    struct cftype *cft,
+				    struct file *file, char __user *buf,
+				    size_t nbytes, loff_t *ppos)
+{
+	char *page;
+	ssize_t retval = 0;
+	struct cgroupfs_root *root = cgrp->root;
+	struct list_head *l;
+	int cnt = 0;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	/* truncate a buffer beyond page size */
+	l = root->leadopt_list.next;
+	while (l != &root->leadopt_list) {
+		struct leadopt_entry *link =
+			list_entry(l, struct leadopt_entry, leadopt_link);
+		cnt += snprintf(page + cnt, max((int)PAGE_SIZE - cnt, 0),
+						"uid:%4d\tleadto:%s\n",
+						link->uid, link->pathname);
+		l = l->next;
+	}
+	retval = simple_read_from_buffer(buf, nbytes, ppos, page, strlen(page));
+
+	free_page((unsigned long)page);
+	return retval;
+}
+
 /* The various types of files and directories in a cgroup file system */
 enum cgroup_filetype {
 	FILE_ROOT,
@@ -1289,6 +1462,7 @@ enum cgroup_filetype {
 	FILE_TASKLIST,
 	FILE_NOTIFY_ON_RELEASE,
 	FILE_RELEASE_AGENT,
+	FILE_LEAD_OPTION,
 };

 static ssize_t cgroup_write_u64(struct cgroup *cgrp, struct cftype *cft,
@@ -1372,6 +1546,12 @@ static ssize_t cgroup_common_file_write(
 		BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
 		strcpy(cgrp->root->release_agent_path, buffer);
 		break;
+	case FILE_LEAD_OPTION:
+		if (cgroup_leadopt_file_write(cgrp->root, buffer) != 1) {
+			retval = -EINVAL;
+			goto out2;
+		}
+		break;
 	default:
 		retval = -EINVAL;
 		goto out2;
@@ -2189,6 +2369,13 @@ static struct cftype cft_release_agent =
 	.private = FILE_RELEASE_AGENT,
 };

+static struct cftype cft_lead_option = {
+	.name = "lead_option",
+	.read = cgroup_leadopt_read,
+	.write = cgroup_common_file_write,
+	.private = FILE_LEAD_OPTION,
+};
+
 static int cgroup_populate_dir(struct cgroup *cgrp)
 {
 	int err;
@@ -2206,6 +2393,11 @@ static int cgroup_populate_dir(struct cg
 			return err;
 	}

+	if (cgrp == cgrp->top_cgroup) {
+		if ((err = cgroup_add_file(cgrp, NULL, &cft_lead_option)) < 0)
+			return err;
+	}
+
 	for_each_subsys(cgrp->root, ss) {
 		if (ss->populate && (err = ss->populate(ss, cgrp)) < 0)
 			return err;
--
-

_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list