mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 17:59:32 +00:00
cgroup: introduce cancel_attach()
Add cancel_attach() operation to struct cgroup_subsys. cancel_attach() can be used when can_attach() operation prepares something for the subsys, but we should rollback what can_attach() operation has prepared if attach task fails after we've succeeded in can_attach(). Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Reviewed-by: Paul Menage <menage@google.com> Cc: Balbir Singh <balbir@linux.vnet.ibm.com> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
5ce9f07bf1
commit
2468c7234b
3 changed files with 47 additions and 8 deletions
|
@ -536,10 +536,21 @@ returns an error, this will abort the attach operation. If a NULL
|
||||||
task is passed, then a successful result indicates that *any*
|
task is passed, then a successful result indicates that *any*
|
||||||
unspecified task can be moved into the cgroup. Note that this isn't
|
unspecified task can be moved into the cgroup. Note that this isn't
|
||||||
called on a fork. If this method returns 0 (success) then this should
|
called on a fork. If this method returns 0 (success) then this should
|
||||||
remain valid while the caller holds cgroup_mutex. If threadgroup is
|
remain valid while the caller holds cgroup_mutex and it is ensured that either
|
||||||
|
attach() or cancel_attach() will be called in future. If threadgroup is
|
||||||
true, then a successful result indicates that all threads in the given
|
true, then a successful result indicates that all threads in the given
|
||||||
thread's threadgroup can be moved together.
|
thread's threadgroup can be moved together.
|
||||||
|
|
||||||
|
void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
|
struct task_struct *task, bool threadgroup)
|
||||||
|
(cgroup_mutex held by caller)
|
||||||
|
|
||||||
|
Called when a task attach operation has failed after can_attach() has succeeded.
|
||||||
|
A subsystem whose can_attach() has some side-effects should provide this
|
||||||
|
function, so that the subsytem can implement a rollback. If not, not necessary.
|
||||||
|
This will be called only about subsystems whose can_attach() operation have
|
||||||
|
succeeded.
|
||||||
|
|
||||||
void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
struct cgroup *old_cgrp, struct task_struct *task,
|
struct cgroup *old_cgrp, struct task_struct *task,
|
||||||
bool threadgroup)
|
bool threadgroup)
|
||||||
|
|
|
@ -428,6 +428,8 @@ struct cgroup_subsys {
|
||||||
void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
|
void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
|
||||||
int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
struct task_struct *tsk, bool threadgroup);
|
struct task_struct *tsk, bool threadgroup);
|
||||||
|
void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
|
struct task_struct *tsk, bool threadgroup);
|
||||||
void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
struct cgroup *old_cgrp, struct task_struct *tsk,
|
struct cgroup *old_cgrp, struct task_struct *tsk,
|
||||||
bool threadgroup);
|
bool threadgroup);
|
||||||
|
|
|
@ -1554,7 +1554,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
|
||||||
int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct cgroup_subsys *ss;
|
struct cgroup_subsys *ss, *failed_ss = NULL;
|
||||||
struct cgroup *oldcgrp;
|
struct cgroup *oldcgrp;
|
||||||
struct css_set *cg;
|
struct css_set *cg;
|
||||||
struct css_set *newcg;
|
struct css_set *newcg;
|
||||||
|
@ -1568,8 +1568,16 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||||
for_each_subsys(root, ss) {
|
for_each_subsys(root, ss) {
|
||||||
if (ss->can_attach) {
|
if (ss->can_attach) {
|
||||||
retval = ss->can_attach(ss, cgrp, tsk, false);
|
retval = ss->can_attach(ss, cgrp, tsk, false);
|
||||||
if (retval)
|
if (retval) {
|
||||||
return retval;
|
/*
|
||||||
|
* Remember on which subsystem the can_attach()
|
||||||
|
* failed, so that we only call cancel_attach()
|
||||||
|
* against the subsystems whose can_attach()
|
||||||
|
* succeeded. (See below)
|
||||||
|
*/
|
||||||
|
failed_ss = ss;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1583,14 +1591,17 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||||
*/
|
*/
|
||||||
newcg = find_css_set(cg, cgrp);
|
newcg = find_css_set(cg, cgrp);
|
||||||
put_css_set(cg);
|
put_css_set(cg);
|
||||||
if (!newcg)
|
if (!newcg) {
|
||||||
return -ENOMEM;
|
retval = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
task_lock(tsk);
|
task_lock(tsk);
|
||||||
if (tsk->flags & PF_EXITING) {
|
if (tsk->flags & PF_EXITING) {
|
||||||
task_unlock(tsk);
|
task_unlock(tsk);
|
||||||
put_css_set(newcg);
|
put_css_set(newcg);
|
||||||
return -ESRCH;
|
retval = -ESRCH;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
rcu_assign_pointer(tsk->cgroups, newcg);
|
rcu_assign_pointer(tsk->cgroups, newcg);
|
||||||
task_unlock(tsk);
|
task_unlock(tsk);
|
||||||
|
@ -1616,7 +1627,22 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
||||||
* is no longer empty.
|
* is no longer empty.
|
||||||
*/
|
*/
|
||||||
cgroup_wakeup_rmdir_waiter(cgrp);
|
cgroup_wakeup_rmdir_waiter(cgrp);
|
||||||
return 0;
|
out:
|
||||||
|
if (retval) {
|
||||||
|
for_each_subsys(root, ss) {
|
||||||
|
if (ss == failed_ss)
|
||||||
|
/*
|
||||||
|
* This subsystem was the one that failed the
|
||||||
|
* can_attach() check earlier, so we don't need
|
||||||
|
* to call cancel_attach() against it or any
|
||||||
|
* remaining subsystems.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
if (ss->cancel_attach)
|
||||||
|
ss->cancel_attach(ss, cgrp, tsk, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue