Commit 2468c7234b366eeb799ee0648cb58f9cba394a54
Committed by
Linus Torvalds
1 parent
5ce9f07bf1
Exists in
master
and in
7 other branches
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>
Showing 3 changed files with 47 additions and 8 deletions Side-by-side Diff
Documentation/cgroups/cgroups.txt
... | ... | @@ -536,9 +536,20 @@ |
536 | 536 | task is passed, then a successful result indicates that *any* |
537 | 537 | unspecified task can be moved into the cgroup. Note that this isn't |
538 | 538 | called on a fork. If this method returns 0 (success) then this should |
539 | -remain valid while the caller holds cgroup_mutex. If threadgroup is | |
539 | +remain valid while the caller holds cgroup_mutex and it is ensured that either | |
540 | +attach() or cancel_attach() will be called in future. If threadgroup is | |
540 | 541 | true, then a successful result indicates that all threads in the given |
541 | 542 | thread's threadgroup can be moved together. |
543 | + | |
544 | +void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | |
545 | + struct task_struct *task, bool threadgroup) | |
546 | +(cgroup_mutex held by caller) | |
547 | + | |
548 | +Called when a task attach operation has failed after can_attach() has succeeded. | |
549 | +A subsystem whose can_attach() has some side-effects should provide this | |
550 | +function, so that the subsytem can implement a rollback. If not, not necessary. | |
551 | +This will be called only about subsystems whose can_attach() operation have | |
552 | +succeeded. | |
542 | 553 | |
543 | 554 | void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
544 | 555 | struct cgroup *old_cgrp, struct task_struct *task, |
include/linux/cgroup.h
... | ... | @@ -428,6 +428,8 @@ |
428 | 428 | void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); |
429 | 429 | int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, |
430 | 430 | struct task_struct *tsk, bool threadgroup); |
431 | + void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, | |
432 | + struct task_struct *tsk, bool threadgroup); | |
431 | 433 | void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, |
432 | 434 | struct cgroup *old_cgrp, struct task_struct *tsk, |
433 | 435 | bool threadgroup); |
kernel/cgroup.c
... | ... | @@ -1554,7 +1554,7 @@ |
1554 | 1554 | int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) |
1555 | 1555 | { |
1556 | 1556 | int retval = 0; |
1557 | - struct cgroup_subsys *ss; | |
1557 | + struct cgroup_subsys *ss, *failed_ss = NULL; | |
1558 | 1558 | struct cgroup *oldcgrp; |
1559 | 1559 | struct css_set *cg; |
1560 | 1560 | struct css_set *newcg; |
... | ... | @@ -1568,8 +1568,16 @@ |
1568 | 1568 | for_each_subsys(root, ss) { |
1569 | 1569 | if (ss->can_attach) { |
1570 | 1570 | retval = ss->can_attach(ss, cgrp, tsk, false); |
1571 | - if (retval) | |
1572 | - return retval; | |
1571 | + if (retval) { | |
1572 | + /* | |
1573 | + * Remember on which subsystem the can_attach() | |
1574 | + * failed, so that we only call cancel_attach() | |
1575 | + * against the subsystems whose can_attach() | |
1576 | + * succeeded. (See below) | |
1577 | + */ | |
1578 | + failed_ss = ss; | |
1579 | + goto out; | |
1580 | + } | |
1573 | 1581 | } |
1574 | 1582 | } |
1575 | 1583 | |
1576 | 1584 | |
... | ... | @@ -1583,14 +1591,17 @@ |
1583 | 1591 | */ |
1584 | 1592 | newcg = find_css_set(cg, cgrp); |
1585 | 1593 | put_css_set(cg); |
1586 | - if (!newcg) | |
1587 | - return -ENOMEM; | |
1594 | + if (!newcg) { | |
1595 | + retval = -ENOMEM; | |
1596 | + goto out; | |
1597 | + } | |
1588 | 1598 | |
1589 | 1599 | task_lock(tsk); |
1590 | 1600 | if (tsk->flags & PF_EXITING) { |
1591 | 1601 | task_unlock(tsk); |
1592 | 1602 | put_css_set(newcg); |
1593 | - return -ESRCH; | |
1603 | + retval = -ESRCH; | |
1604 | + goto out; | |
1594 | 1605 | } |
1595 | 1606 | rcu_assign_pointer(tsk->cgroups, newcg); |
1596 | 1607 | task_unlock(tsk); |
... | ... | @@ -1616,7 +1627,22 @@ |
1616 | 1627 | * is no longer empty. |
1617 | 1628 | */ |
1618 | 1629 | cgroup_wakeup_rmdir_waiter(cgrp); |
1619 | - return 0; | |
1630 | +out: | |
1631 | + if (retval) { | |
1632 | + for_each_subsys(root, ss) { | |
1633 | + if (ss == failed_ss) | |
1634 | + /* | |
1635 | + * This subsystem was the one that failed the | |
1636 | + * can_attach() check earlier, so we don't need | |
1637 | + * to call cancel_attach() against it or any | |
1638 | + * remaining subsystems. | |
1639 | + */ | |
1640 | + break; | |
1641 | + if (ss->cancel_attach) | |
1642 | + ss->cancel_attach(ss, cgrp, tsk, false); | |
1643 | + } | |
1644 | + } | |
1645 | + return retval; | |
1620 | 1646 | } |
1621 | 1647 | |
1622 | 1648 | /* |