Commit 2468c7234b366eeb799ee0648cb58f9cba394a54

Authored by Daisuke Nishimura
Committed by Linus Torvalds
1 parent 5ce9f07bf1

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);
... ... @@ -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 /*