diff options
author | Tejun Heo <tj@kernel.org> | 2015-10-15 16:41:49 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2015-10-15 16:41:49 -0400 |
commit | 0de0942db2b36dd91c088a7950398d2e87f23b23 (patch) | |
tree | 27641a8e1c0639ea209f8b171b0eb191afc7118d | |
parent | b309e5b743a999cdb34a3989d1800c608e656c2b (diff) |
cgroup: make cgroup->nr_populated count the number of populated css_sets
Currently, cgroup->nr_populated counts whether the cgroup has any
css_sets linked to it and the number of children which has non-zero
->nr_populated. This works because a css_set's refcnt converges with
the number of tasks linked to it and thus there's no css_set linked to
a cgroup if it doesn't have any live tasks.
To help tracking resource usage of zombie tasks, putting the ref of
css_set will be separated from disassociating the task from the
css_set which means that a cgroup may have css_sets linked to it even
when it doesn't have any live tasks.
This patch updates cgroup->nr_populated so that for the cgroup itself
it counts the number of css_sets which have tasks associated with them
so that empty css_sets don't skew the populated test.
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | include/linux/cgroup-defs.h | 8 | ||||
-rw-r--r-- | kernel/cgroup.c | 65 |
2 files changed, 56 insertions, 17 deletions
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index df589a097539..17444505c870 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h | |||
@@ -232,10 +232,10 @@ struct cgroup { | |||
232 | int id; | 232 | int id; |
233 | 233 | ||
234 | /* | 234 | /* |
235 | * If this cgroup contains any tasks, it contributes one to | 235 | * Each non-empty css_set associated with this cgroup contributes |
236 | * populated_cnt. All children with non-zero popuplated_cnt of | 236 | * one to populated_cnt. All children with non-zero popuplated_cnt |
237 | * their own contribute one. The count is zero iff there's no task | 237 | * of their own contribute one. The count is zero iff there's no |
238 | * in this cgroup or its subtree. | 238 | * task in this cgroup or its subtree. |
239 | */ | 239 | */ |
240 | int populated_cnt; | 240 | int populated_cnt; |
241 | 241 | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 49f30f1b7e0a..e5231d045eb9 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -582,14 +582,25 @@ struct css_set init_css_set = { | |||
582 | static int css_set_count = 1; /* 1 for init_css_set */ | 582 | static int css_set_count = 1; /* 1 for init_css_set */ |
583 | 583 | ||
584 | /** | 584 | /** |
585 | * css_set_populated - does a css_set contain any tasks? | ||
586 | * @cset: target css_set | ||
587 | */ | ||
588 | static bool css_set_populated(struct css_set *cset) | ||
589 | { | ||
590 | lockdep_assert_held(&css_set_rwsem); | ||
591 | |||
592 | return !list_empty(&cset->tasks) || !list_empty(&cset->mg_tasks); | ||
593 | } | ||
594 | |||
595 | /** | ||
585 | * cgroup_update_populated - updated populated count of a cgroup | 596 | * cgroup_update_populated - updated populated count of a cgroup |
586 | * @cgrp: the target cgroup | 597 | * @cgrp: the target cgroup |
587 | * @populated: inc or dec populated count | 598 | * @populated: inc or dec populated count |
588 | * | 599 | * |
589 | * @cgrp is either getting the first task (css_set) or losing the last. | 600 | * One of the css_sets associated with @cgrp is either getting its first |
590 | * Update @cgrp->populated_cnt accordingly. The count is propagated | 601 | * task or losing the last. Update @cgrp->populated_cnt accordingly. The |
591 | * towards root so that a given cgroup's populated_cnt is zero iff the | 602 | * count is propagated towards root so that a given cgroup's populated_cnt |
592 | * cgroup and all its descendants are empty. | 603 | * is zero iff the cgroup and all its descendants don't contain any tasks. |
593 | * | 604 | * |
594 | * @cgrp's interface file "cgroup.populated" is zero if | 605 | * @cgrp's interface file "cgroup.populated" is zero if |
595 | * @cgrp->populated_cnt is zero and 1 otherwise. When @cgrp->populated_cnt | 606 | * @cgrp->populated_cnt is zero and 1 otherwise. When @cgrp->populated_cnt |
@@ -618,6 +629,24 @@ static void cgroup_update_populated(struct cgroup *cgrp, bool populated) | |||
618 | } while (cgrp); | 629 | } while (cgrp); |
619 | } | 630 | } |
620 | 631 | ||
632 | /** | ||
633 | * css_set_update_populated - update populated state of a css_set | ||
634 | * @cset: target css_set | ||
635 | * @populated: whether @cset is populated or depopulated | ||
636 | * | ||
637 | * @cset is either getting the first task or losing the last. Update the | ||
638 | * ->populated_cnt of all associated cgroups accordingly. | ||
639 | */ | ||
640 | static void css_set_update_populated(struct css_set *cset, bool populated) | ||
641 | { | ||
642 | struct cgrp_cset_link *link; | ||
643 | |||
644 | lockdep_assert_held(&css_set_rwsem); | ||
645 | |||
646 | list_for_each_entry(link, &cset->cgrp_links, cgrp_link) | ||
647 | cgroup_update_populated(link->cgrp, populated); | ||
648 | } | ||
649 | |||
621 | /* | 650 | /* |
622 | * hash table for cgroup groups. This improves the performance to find | 651 | * hash table for cgroup groups. This improves the performance to find |
623 | * an existing css_set. This hash doesn't (currently) take into | 652 | * an existing css_set. This hash doesn't (currently) take into |
@@ -663,10 +692,8 @@ static void put_css_set_locked(struct css_set *cset) | |||
663 | list_del(&link->cgrp_link); | 692 | list_del(&link->cgrp_link); |
664 | 693 | ||
665 | /* @cgrp can't go away while we're holding css_set_rwsem */ | 694 | /* @cgrp can't go away while we're holding css_set_rwsem */ |
666 | if (list_empty(&cgrp->cset_links)) { | 695 | if (list_empty(&cgrp->cset_links)) |
667 | cgroup_update_populated(cgrp, false); | ||
668 | check_for_release(cgrp); | 696 | check_for_release(cgrp); |
669 | } | ||
670 | 697 | ||
671 | kfree(link); | 698 | kfree(link); |
672 | } | 699 | } |
@@ -875,8 +902,6 @@ static void link_css_set(struct list_head *tmp_links, struct css_set *cset, | |||
875 | link->cset = cset; | 902 | link->cset = cset; |
876 | link->cgrp = cgrp; | 903 | link->cgrp = cgrp; |
877 | 904 | ||
878 | if (list_empty(&cgrp->cset_links)) | ||
879 | cgroup_update_populated(cgrp, true); | ||
880 | list_move(&link->cset_link, &cgrp->cset_links); | 905 | list_move(&link->cset_link, &cgrp->cset_links); |
881 | 906 | ||
882 | /* | 907 | /* |
@@ -1754,6 +1779,8 @@ static void cgroup_enable_task_cg_lists(void) | |||
1754 | if (!(p->flags & PF_EXITING)) { | 1779 | if (!(p->flags & PF_EXITING)) { |
1755 | struct css_set *cset = task_css_set(p); | 1780 | struct css_set *cset = task_css_set(p); |
1756 | 1781 | ||
1782 | if (!css_set_populated(cset)) | ||
1783 | css_set_update_populated(cset, true); | ||
1757 | list_add(&p->cg_list, &cset->tasks); | 1784 | list_add(&p->cg_list, &cset->tasks); |
1758 | get_css_set(cset); | 1785 | get_css_set(cset); |
1759 | } | 1786 | } |
@@ -1868,8 +1895,11 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask) | |||
1868 | * objects. | 1895 | * objects. |
1869 | */ | 1896 | */ |
1870 | down_write(&css_set_rwsem); | 1897 | down_write(&css_set_rwsem); |
1871 | hash_for_each(css_set_table, i, cset, hlist) | 1898 | hash_for_each(css_set_table, i, cset, hlist) { |
1872 | link_css_set(&tmp_links, cset, root_cgrp); | 1899 | link_css_set(&tmp_links, cset, root_cgrp); |
1900 | if (css_set_populated(cset)) | ||
1901 | cgroup_update_populated(root_cgrp, true); | ||
1902 | } | ||
1873 | up_write(&css_set_rwsem); | 1903 | up_write(&css_set_rwsem); |
1874 | 1904 | ||
1875 | BUG_ON(!list_empty(&root_cgrp->self.children)); | 1905 | BUG_ON(!list_empty(&root_cgrp->self.children)); |
@@ -2256,10 +2286,16 @@ static void cgroup_task_migrate(struct task_struct *tsk, | |||
2256 | WARN_ON_ONCE(tsk->flags & PF_EXITING); | 2286 | WARN_ON_ONCE(tsk->flags & PF_EXITING); |
2257 | old_cset = task_css_set(tsk); | 2287 | old_cset = task_css_set(tsk); |
2258 | 2288 | ||
2289 | if (!css_set_populated(new_cset)) | ||
2290 | css_set_update_populated(new_cset, true); | ||
2291 | |||
2259 | get_css_set(new_cset); | 2292 | get_css_set(new_cset); |
2260 | rcu_assign_pointer(tsk->cgroups, new_cset); | 2293 | rcu_assign_pointer(tsk->cgroups, new_cset); |
2261 | list_move_tail(&tsk->cg_list, &new_cset->mg_tasks); | 2294 | list_move_tail(&tsk->cg_list, &new_cset->mg_tasks); |
2262 | 2295 | ||
2296 | if (!css_set_populated(old_cset)) | ||
2297 | css_set_update_populated(old_cset, false); | ||
2298 | |||
2263 | /* | 2299 | /* |
2264 | * We just gained a reference on old_cset by taking it from the | 2300 | * We just gained a reference on old_cset by taking it from the |
2265 | * task. As trading it for new_cset is protected by cgroup_mutex, | 2301 | * task. As trading it for new_cset is protected by cgroup_mutex, |
@@ -3774,7 +3810,7 @@ static void css_advance_task_iter(struct css_task_iter *it) | |||
3774 | link = list_entry(l, struct cgrp_cset_link, cset_link); | 3810 | link = list_entry(l, struct cgrp_cset_link, cset_link); |
3775 | cset = link->cset; | 3811 | cset = link->cset; |
3776 | } | 3812 | } |
3777 | } while (list_empty(&cset->tasks) && list_empty(&cset->mg_tasks)); | 3813 | } while (!css_set_populated(cset)); |
3778 | 3814 | ||
3779 | it->cset_pos = l; | 3815 | it->cset_pos = l; |
3780 | 3816 | ||
@@ -5492,17 +5528,20 @@ void cgroup_exit(struct task_struct *tsk) | |||
5492 | 5528 | ||
5493 | /* | 5529 | /* |
5494 | * Unlink from @tsk from its css_set. As migration path can't race | 5530 | * Unlink from @tsk from its css_set. As migration path can't race |
5495 | * with us, we can check cg_list without grabbing css_set_rwsem. | 5531 | * with us, we can check css_set and cg_list without synchronization. |
5496 | */ | 5532 | */ |
5533 | cset = task_css_set(tsk); | ||
5534 | |||
5497 | if (!list_empty(&tsk->cg_list)) { | 5535 | if (!list_empty(&tsk->cg_list)) { |
5498 | down_write(&css_set_rwsem); | 5536 | down_write(&css_set_rwsem); |
5499 | list_del_init(&tsk->cg_list); | 5537 | list_del_init(&tsk->cg_list); |
5538 | if (!css_set_populated(cset)) | ||
5539 | css_set_update_populated(cset, false); | ||
5500 | up_write(&css_set_rwsem); | 5540 | up_write(&css_set_rwsem); |
5501 | put_cset = true; | 5541 | put_cset = true; |
5502 | } | 5542 | } |
5503 | 5543 | ||
5504 | /* Reassign the task to the init_css_set. */ | 5544 | /* Reassign the task to the init_css_set. */ |
5505 | cset = task_css_set(tsk); | ||
5506 | RCU_INIT_POINTER(tsk->cgroups, &init_css_set); | 5545 | RCU_INIT_POINTER(tsk->cgroups, &init_css_set); |
5507 | 5546 | ||
5508 | /* see cgroup_post_fork() for details */ | 5547 | /* see cgroup_post_fork() for details */ |