diff options
-rw-r--r-- | include/linux/cgroup.h | 6 | ||||
-rw-r--r-- | kernel/cgroup/cgroup.c | 77 |
2 files changed, 66 insertions, 17 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index b7dd23040cd5..79faa6467f76 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -38,6 +38,8 @@ | |||
38 | 38 | ||
39 | /* walk only threadgroup leaders */ | 39 | /* walk only threadgroup leaders */ |
40 | #define CSS_TASK_ITER_PROCS (1U << 0) | 40 | #define CSS_TASK_ITER_PROCS (1U << 0) |
41 | /* walk all threaded css_sets in the domain */ | ||
42 | #define CSS_TASK_ITER_THREADED (1U << 1) | ||
41 | 43 | ||
42 | /* a css_task_iter should be treated as an opaque object */ | 44 | /* a css_task_iter should be treated as an opaque object */ |
43 | struct css_task_iter { | 45 | struct css_task_iter { |
@@ -47,11 +49,15 @@ struct css_task_iter { | |||
47 | struct list_head *cset_pos; | 49 | struct list_head *cset_pos; |
48 | struct list_head *cset_head; | 50 | struct list_head *cset_head; |
49 | 51 | ||
52 | struct list_head *tcset_pos; | ||
53 | struct list_head *tcset_head; | ||
54 | |||
50 | struct list_head *task_pos; | 55 | struct list_head *task_pos; |
51 | struct list_head *tasks_head; | 56 | struct list_head *tasks_head; |
52 | struct list_head *mg_tasks_head; | 57 | struct list_head *mg_tasks_head; |
53 | 58 | ||
54 | struct css_set *cur_cset; | 59 | struct css_set *cur_cset; |
60 | struct css_set *cur_dcset; | ||
55 | struct task_struct *cur_task; | 61 | struct task_struct *cur_task; |
56 | struct list_head iters_node; /* css_set->task_iters */ | 62 | struct list_head iters_node; /* css_set->task_iters */ |
57 | }; | 63 | }; |
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index c7e1c243b77d..a1d59af274a9 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c | |||
@@ -3629,6 +3629,58 @@ bool css_has_online_children(struct cgroup_subsys_state *css) | |||
3629 | return ret; | 3629 | return ret; |
3630 | } | 3630 | } |
3631 | 3631 | ||
3632 | static struct css_set *css_task_iter_next_css_set(struct css_task_iter *it) | ||
3633 | { | ||
3634 | struct list_head *l; | ||
3635 | struct cgrp_cset_link *link; | ||
3636 | struct css_set *cset; | ||
3637 | |||
3638 | lockdep_assert_held(&css_set_lock); | ||
3639 | |||
3640 | /* find the next threaded cset */ | ||
3641 | if (it->tcset_pos) { | ||
3642 | l = it->tcset_pos->next; | ||
3643 | |||
3644 | if (l != it->tcset_head) { | ||
3645 | it->tcset_pos = l; | ||
3646 | return container_of(l, struct css_set, | ||
3647 | threaded_csets_node); | ||
3648 | } | ||
3649 | |||
3650 | it->tcset_pos = NULL; | ||
3651 | } | ||
3652 | |||
3653 | /* find the next cset */ | ||
3654 | l = it->cset_pos; | ||
3655 | l = l->next; | ||
3656 | if (l == it->cset_head) { | ||
3657 | it->cset_pos = NULL; | ||
3658 | return NULL; | ||
3659 | } | ||
3660 | |||
3661 | if (it->ss) { | ||
3662 | cset = container_of(l, struct css_set, e_cset_node[it->ss->id]); | ||
3663 | } else { | ||
3664 | link = list_entry(l, struct cgrp_cset_link, cset_link); | ||
3665 | cset = link->cset; | ||
3666 | } | ||
3667 | |||
3668 | it->cset_pos = l; | ||
3669 | |||
3670 | /* initialize threaded css_set walking */ | ||
3671 | if (it->flags & CSS_TASK_ITER_THREADED) { | ||
3672 | if (it->cur_dcset) | ||
3673 | put_css_set_locked(it->cur_dcset); | ||
3674 | it->cur_dcset = cset; | ||
3675 | get_css_set(cset); | ||
3676 | |||
3677 | it->tcset_head = &cset->threaded_csets; | ||
3678 | it->tcset_pos = &cset->threaded_csets; | ||
3679 | } | ||
3680 | |||
3681 | return cset; | ||
3682 | } | ||
3683 | |||
3632 | /** | 3684 | /** |
3633 | * css_task_iter_advance_css_set - advance a task itererator to the next css_set | 3685 | * css_task_iter_advance_css_set - advance a task itererator to the next css_set |
3634 | * @it: the iterator to advance | 3686 | * @it: the iterator to advance |
@@ -3637,32 +3689,19 @@ bool css_has_online_children(struct cgroup_subsys_state *css) | |||
3637 | */ | 3689 | */ |
3638 | static void css_task_iter_advance_css_set(struct css_task_iter *it) | 3690 | static void css_task_iter_advance_css_set(struct css_task_iter *it) |
3639 | { | 3691 | { |
3640 | struct list_head *l = it->cset_pos; | ||
3641 | struct cgrp_cset_link *link; | ||
3642 | struct css_set *cset; | 3692 | struct css_set *cset; |
3643 | 3693 | ||
3644 | lockdep_assert_held(&css_set_lock); | 3694 | lockdep_assert_held(&css_set_lock); |
3645 | 3695 | ||
3646 | /* Advance to the next non-empty css_set */ | 3696 | /* Advance to the next non-empty css_set */ |
3647 | do { | 3697 | do { |
3648 | l = l->next; | 3698 | cset = css_task_iter_next_css_set(it); |
3649 | if (l == it->cset_head) { | 3699 | if (!cset) { |
3650 | it->cset_pos = NULL; | ||
3651 | it->task_pos = NULL; | 3700 | it->task_pos = NULL; |
3652 | return; | 3701 | return; |
3653 | } | 3702 | } |
3654 | |||
3655 | if (it->ss) { | ||
3656 | cset = container_of(l, struct css_set, | ||
3657 | e_cset_node[it->ss->id]); | ||
3658 | } else { | ||
3659 | link = list_entry(l, struct cgrp_cset_link, cset_link); | ||
3660 | cset = link->cset; | ||
3661 | } | ||
3662 | } while (!css_set_populated(cset)); | 3703 | } while (!css_set_populated(cset)); |
3663 | 3704 | ||
3664 | it->cset_pos = l; | ||
3665 | |||
3666 | if (!list_empty(&cset->tasks)) | 3705 | if (!list_empty(&cset->tasks)) |
3667 | it->task_pos = cset->tasks.next; | 3706 | it->task_pos = cset->tasks.next; |
3668 | else | 3707 | else |
@@ -3805,6 +3844,9 @@ void css_task_iter_end(struct css_task_iter *it) | |||
3805 | spin_unlock_irq(&css_set_lock); | 3844 | spin_unlock_irq(&css_set_lock); |
3806 | } | 3845 | } |
3807 | 3846 | ||
3847 | if (it->cur_dcset) | ||
3848 | put_css_set(it->cur_dcset); | ||
3849 | |||
3808 | if (it->cur_task) | 3850 | if (it->cur_task) |
3809 | put_task_struct(it->cur_task); | 3851 | put_task_struct(it->cur_task); |
3810 | } | 3852 | } |
@@ -3830,6 +3872,7 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos) | |||
3830 | struct kernfs_open_file *of = s->private; | 3872 | struct kernfs_open_file *of = s->private; |
3831 | struct cgroup *cgrp = seq_css(s)->cgroup; | 3873 | struct cgroup *cgrp = seq_css(s)->cgroup; |
3832 | struct css_task_iter *it = of->priv; | 3874 | struct css_task_iter *it = of->priv; |
3875 | unsigned iter_flags = CSS_TASK_ITER_PROCS | CSS_TASK_ITER_THREADED; | ||
3833 | 3876 | ||
3834 | /* | 3877 | /* |
3835 | * When a seq_file is seeked, it's always traversed sequentially | 3878 | * When a seq_file is seeked, it's always traversed sequentially |
@@ -3843,10 +3886,10 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos) | |||
3843 | if (!it) | 3886 | if (!it) |
3844 | return ERR_PTR(-ENOMEM); | 3887 | return ERR_PTR(-ENOMEM); |
3845 | of->priv = it; | 3888 | of->priv = it; |
3846 | css_task_iter_start(&cgrp->self, CSS_TASK_ITER_PROCS, it); | 3889 | css_task_iter_start(&cgrp->self, iter_flags, it); |
3847 | } else if (!(*pos)++) { | 3890 | } else if (!(*pos)++) { |
3848 | css_task_iter_end(it); | 3891 | css_task_iter_end(it); |
3849 | css_task_iter_start(&cgrp->self, CSS_TASK_ITER_PROCS, it); | 3892 | css_task_iter_start(&cgrp->self, iter_flags, it); |
3850 | } | 3893 | } |
3851 | 3894 | ||
3852 | return cgroup_procs_next(s, NULL, NULL); | 3895 | return cgroup_procs_next(s, NULL, NULL); |