aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-10-15 16:41:49 -0400
committerTejun Heo <tj@kernel.org>2015-10-15 16:41:49 -0400
commit0de0942db2b36dd91c088a7950398d2e87f23b23 (patch)
tree27641a8e1c0639ea209f8b171b0eb191afc7118d
parentb309e5b743a999cdb34a3989d1800c608e656c2b (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.h8
-rw-r--r--kernel/cgroup.c65
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 = {
582static int css_set_count = 1; /* 1 for init_css_set */ 582static 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 */
588static 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 */
640static 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 */