cgroup: introduce cgroup_taskset and use it in subsys->can_attach(), cancel_attach() and attach()
Currently, there's no way to pass multiple tasks to cgroup_subsys methods necessitating the need for separate per-process and per-task methods. This patch introduces cgroup_taskset which can be used to pass multiple tasks and their associated cgroups to cgroup_subsys methods. Three methods - can_attach(), cancel_attach() and attach() - are converted to use cgroup_taskset. This unifies passed parameters so that all methods have access to all information. Conversions in this patchset are identical and don't introduce any behavior change. -v2: documentation updated as per Paul Menage's suggestion. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Reviewed-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Paul Menage <paul@paulmenage.org> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: James Morris <jmorris@namei.org>
This commit is contained in:
@@ -1757,11 +1757,85 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cgroup_path);
|
||||
|
||||
/*
|
||||
* Control Group taskset
|
||||
*/
|
||||
struct task_and_cgroup {
|
||||
struct task_struct *task;
|
||||
struct cgroup *cgrp;
|
||||
};
|
||||
|
||||
struct cgroup_taskset {
|
||||
struct task_and_cgroup single;
|
||||
struct flex_array *tc_array;
|
||||
int tc_array_len;
|
||||
int idx;
|
||||
struct cgroup *cur_cgrp;
|
||||
};
|
||||
|
||||
/**
|
||||
* cgroup_taskset_first - reset taskset and return the first task
|
||||
* @tset: taskset of interest
|
||||
*
|
||||
* @tset iteration is initialized and the first task is returned.
|
||||
*/
|
||||
struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset)
|
||||
{
|
||||
if (tset->tc_array) {
|
||||
tset->idx = 0;
|
||||
return cgroup_taskset_next(tset);
|
||||
} else {
|
||||
tset->cur_cgrp = tset->single.cgrp;
|
||||
return tset->single.task;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cgroup_taskset_first);
|
||||
|
||||
/**
|
||||
* cgroup_taskset_next - iterate to the next task in taskset
|
||||
* @tset: taskset of interest
|
||||
*
|
||||
* Return the next task in @tset. Iteration must have been initialized
|
||||
* with cgroup_taskset_first().
|
||||
*/
|
||||
struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
|
||||
{
|
||||
struct task_and_cgroup *tc;
|
||||
|
||||
if (!tset->tc_array || tset->idx >= tset->tc_array_len)
|
||||
return NULL;
|
||||
|
||||
tc = flex_array_get(tset->tc_array, tset->idx++);
|
||||
tset->cur_cgrp = tc->cgrp;
|
||||
return tc->task;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cgroup_taskset_next);
|
||||
|
||||
/**
|
||||
* cgroup_taskset_cur_cgroup - return the matching cgroup for the current task
|
||||
* @tset: taskset of interest
|
||||
*
|
||||
* Return the cgroup for the current (last returned) task of @tset. This
|
||||
* function must be preceded by either cgroup_taskset_first() or
|
||||
* cgroup_taskset_next().
|
||||
*/
|
||||
struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset)
|
||||
{
|
||||
return tset->cur_cgrp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cgroup_taskset_cur_cgroup);
|
||||
|
||||
/**
|
||||
* cgroup_taskset_size - return the number of tasks in taskset
|
||||
* @tset: taskset of interest
|
||||
*/
|
||||
int cgroup_taskset_size(struct cgroup_taskset *tset)
|
||||
{
|
||||
return tset->tc_array ? tset->tc_array_len : 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cgroup_taskset_size);
|
||||
|
||||
|
||||
/*
|
||||
* cgroup_task_migrate - move a task from one cgroup to another.
|
||||
*
|
||||
@@ -1842,6 +1916,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||
struct cgroup_subsys *ss, *failed_ss = NULL;
|
||||
struct cgroup *oldcgrp;
|
||||
struct cgroupfs_root *root = cgrp->root;
|
||||
struct cgroup_taskset tset = { };
|
||||
|
||||
/* @tsk either already exited or can't exit until the end */
|
||||
if (tsk->flags & PF_EXITING)
|
||||
@@ -1852,9 +1927,12 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||
if (cgrp == oldcgrp)
|
||||
return 0;
|
||||
|
||||
tset.single.task = tsk;
|
||||
tset.single.cgrp = oldcgrp;
|
||||
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss->can_attach) {
|
||||
retval = ss->can_attach(ss, cgrp, tsk);
|
||||
retval = ss->can_attach(ss, cgrp, &tset);
|
||||
if (retval) {
|
||||
/*
|
||||
* Remember on which subsystem the can_attach()
|
||||
@@ -1885,7 +1963,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||
if (ss->attach_task)
|
||||
ss->attach_task(cgrp, tsk);
|
||||
if (ss->attach)
|
||||
ss->attach(ss, cgrp, oldcgrp, tsk);
|
||||
ss->attach(ss, cgrp, &tset);
|
||||
}
|
||||
|
||||
synchronize_rcu();
|
||||
@@ -1907,7 +1985,7 @@ out:
|
||||
*/
|
||||
break;
|
||||
if (ss->cancel_attach)
|
||||
ss->cancel_attach(ss, cgrp, tsk);
|
||||
ss->cancel_attach(ss, cgrp, &tset);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
@@ -2023,6 +2101,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
||||
struct task_struct *tsk;
|
||||
struct task_and_cgroup *tc;
|
||||
struct flex_array *group;
|
||||
struct cgroup_taskset tset = { };
|
||||
/*
|
||||
* we need to make sure we have css_sets for all the tasks we're
|
||||
* going to move -before- we actually start moving them, so that in
|
||||
@@ -2089,6 +2168,8 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
||||
} while_each_thread(leader, tsk);
|
||||
/* remember the number of threads in the array for later. */
|
||||
group_size = i;
|
||||
tset.tc_array = group;
|
||||
tset.tc_array_len = group_size;
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
/* methods shouldn't be called if no task is actually migrating */
|
||||
@@ -2101,7 +2182,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
||||
*/
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss->can_attach) {
|
||||
retval = ss->can_attach(ss, cgrp, leader);
|
||||
retval = ss->can_attach(ss, cgrp, &tset);
|
||||
if (retval) {
|
||||
failed_ss = ss;
|
||||
goto out_cancel_attach;
|
||||
@@ -2183,10 +2264,8 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
||||
* being moved, this call will need to be reworked to communicate that.
|
||||
*/
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss->attach) {
|
||||
tc = flex_array_get(group, 0);
|
||||
ss->attach(ss, cgrp, tc->cgrp, tc->task);
|
||||
}
|
||||
if (ss->attach)
|
||||
ss->attach(ss, cgrp, &tset);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2208,11 +2287,11 @@ out_cancel_attach:
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss == failed_ss) {
|
||||
if (cancel_failed_ss && ss->cancel_attach)
|
||||
ss->cancel_attach(ss, cgrp, leader);
|
||||
ss->cancel_attach(ss, cgrp, &tset);
|
||||
break;
|
||||
}
|
||||
if (ss->cancel_attach)
|
||||
ss->cancel_attach(ss, cgrp, leader);
|
||||
ss->cancel_attach(ss, cgrp, &tset);
|
||||
}
|
||||
}
|
||||
out_put_tasks:
|
||||
|
Reference in New Issue
Block a user