|
@@ -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 retval = 0;
|
|
|
- struct cgroup_subsys *ss;
|
|
|
+ struct cgroup_subsys *ss, *failed_ss = NULL;
|
|
|
struct cgroup *oldcgrp;
|
|
|
struct css_set *cg;
|
|
|
struct css_set *newcg;
|
|
@@ -1568,8 +1568,16 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
|
|
for_each_subsys(root, ss) {
|
|
|
if (ss->can_attach) {
|
|
|
retval = ss->can_attach(ss, cgrp, tsk, false);
|
|
|
- if (retval)
|
|
|
- return retval;
|
|
|
+ if (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);
|
|
|
put_css_set(cg);
|
|
|
- if (!newcg)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!newcg) {
|
|
|
+ retval = -ENOMEM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
task_lock(tsk);
|
|
|
if (tsk->flags & PF_EXITING) {
|
|
|
task_unlock(tsk);
|
|
|
put_css_set(newcg);
|
|
|
- return -ESRCH;
|
|
|
+ retval = -ESRCH;
|
|
|
+ goto out;
|
|
|
}
|
|
|
rcu_assign_pointer(tsk->cgroups, newcg);
|
|
|
task_unlock(tsk);
|
|
@@ -1616,7 +1627,22 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
|
|
|
* is no longer empty.
|
|
|
*/
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/*
|