diff options
author | Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> | 2010-03-10 18:22:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:35 -0500 |
commit | 2468c7234b366eeb799ee0648cb58f9cba394a54 (patch) | |
tree | 050d7ea224b975eb71b05bf472f14f4c7bb13670 | |
parent | 5ce9f07bf1bed9a1f9886373ad0b149294f84c25 (diff) |
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>
-rw-r--r-- | Documentation/cgroups/cgroups.txt | 13 | ||||
-rw-r--r-- | include/linux/cgroup.h | 2 | ||||
-rw-r--r-- | kernel/cgroup.c | 40 |
3 files changed, 47 insertions, 8 deletions
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index 0b33bfe7dde9..d45082653e3d 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt | |||
@@ -536,10 +536,21 @@ returns an error, this will abort the attach operation. If a NULL | |||
536 | task is passed, then a successful result indicates that *any* | 536 | task is passed, then a successful result indicates that *any* |
537 | unspecified task can be moved into the cgroup. Note that this isn't | 537 | unspecified task can be moved into the cgroup. Note that this isn't |
538 | called on a fork. If this method returns 0 (success) then this should | 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 | true, then a successful result indicates that all threads in the given | 541 | true, then a successful result indicates that all threads in the given |
541 | thread's threadgroup can be moved together. | 542 | thread's threadgroup can be moved together. |
542 | 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. | ||
553 | |||
543 | void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | 554 | void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
544 | struct cgroup *old_cgrp, struct task_struct *task, | 555 | struct cgroup *old_cgrp, struct task_struct *task, |
545 | bool threadgroup) | 556 | bool threadgroup) |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index c9bbcb2a75ae..d08cfe7e12e5 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -428,6 +428,8 @@ struct cgroup_subsys { | |||
428 | void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); | 428 | void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); |
429 | int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, | 429 | int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, |
430 | struct task_struct *tsk, bool threadgroup); | 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 | void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, | 433 | void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, |
432 | struct cgroup *old_cgrp, struct task_struct *tsk, | 434 | struct cgroup *old_cgrp, struct task_struct *tsk, |
433 | bool threadgroup); | 435 | bool threadgroup); |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 4fd90e129772..be45d2f6008a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -1554,7 +1554,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen) | |||
1554 | int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 1554 | int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) |
1555 | { | 1555 | { |
1556 | int retval = 0; | 1556 | int retval = 0; |
1557 | struct cgroup_subsys *ss; | 1557 | struct cgroup_subsys *ss, *failed_ss = NULL; |
1558 | struct cgroup *oldcgrp; | 1558 | struct cgroup *oldcgrp; |
1559 | struct css_set *cg; | 1559 | struct css_set *cg; |
1560 | struct css_set *newcg; | 1560 | struct css_set *newcg; |
@@ -1568,8 +1568,16 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1568 | for_each_subsys(root, ss) { | 1568 | for_each_subsys(root, ss) { |
1569 | if (ss->can_attach) { | 1569 | if (ss->can_attach) { |
1570 | retval = ss->can_attach(ss, cgrp, tsk, false); | 1570 | retval = ss->can_attach(ss, cgrp, tsk, false); |
1571 | if (retval) | 1571 | if (retval) { |
1572 | return 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 | ||
@@ -1583,14 +1591,17 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1583 | */ | 1591 | */ |
1584 | newcg = find_css_set(cg, cgrp); | 1592 | newcg = find_css_set(cg, cgrp); |
1585 | put_css_set(cg); | 1593 | put_css_set(cg); |
1586 | if (!newcg) | 1594 | if (!newcg) { |
1587 | return -ENOMEM; | 1595 | retval = -ENOMEM; |
1596 | goto out; | ||
1597 | } | ||
1588 | 1598 | ||
1589 | task_lock(tsk); | 1599 | task_lock(tsk); |
1590 | if (tsk->flags & PF_EXITING) { | 1600 | if (tsk->flags & PF_EXITING) { |
1591 | task_unlock(tsk); | 1601 | task_unlock(tsk); |
1592 | put_css_set(newcg); | 1602 | put_css_set(newcg); |
1593 | return -ESRCH; | 1603 | retval = -ESRCH; |
1604 | goto out; | ||
1594 | } | 1605 | } |
1595 | rcu_assign_pointer(tsk->cgroups, newcg); | 1606 | rcu_assign_pointer(tsk->cgroups, newcg); |
1596 | task_unlock(tsk); | 1607 | task_unlock(tsk); |
@@ -1616,7 +1627,22 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1616 | * is no longer empty. | 1627 | * is no longer empty. |
1617 | */ | 1628 | */ |
1618 | cgroup_wakeup_rmdir_waiter(cgrp); | 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 | /* |