diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 0dcf260a4c1c266b90b07d07e3822925b98e61c0..a60e9966b32d153136fc923f900ba989ef9810b6 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -47,7 +47,6 @@ struct kernel_clone_args; /* internal flags */ #define CSS_TASK_ITER_SKIPPED (1U << 16) -#define CSS_TASK_ITER_STOPPED (1U << 17) /* a css_task_iter should be treated as an opaque object */ struct css_task_iter { diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 37041478c39c636daa4aea0e942b7e55755a05d2..d0a4a1c4c38d2f9fe7879be2b32bba6e6f32b4d1 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -215,8 +215,6 @@ static int cgroup_apply_control(struct cgroup *cgrp); static void cgroup_finalize_control(struct cgroup *cgrp, int ret); static void css_task_iter_skip(struct css_task_iter *it, struct task_struct *task); -static void css_task_iter_stop(struct css_task_iter *it, - struct cgroup_subsys *ss); static int cgroup_destroy_locked(struct cgroup *cgrp); static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, struct cgroup_subsys *ss); @@ -857,19 +855,6 @@ static void css_set_skip_task_iters(struct css_set *cset, css_task_iter_skip(it, task); } -/* - * @cset is moving to other list, it's not safe to continue the iteration, - * because the cset_head of css_task_iter which is from the old list can - * not be used as the stop condition of iteration. - */ -static void css_set_stop_iters(struct css_set *cset, struct cgroup_subsys *ss) -{ - struct css_task_iter *it, *pos; - - list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node) - css_task_iter_stop(it, ss); -} - /** * css_set_move_task - move a task from one css_set to another * @task: task being moved @@ -1728,7 +1713,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) { struct cgroup *dcgrp = &dst_root->cgrp; struct cgroup_subsys *ss; - int ssid, i, ret; + int ssid, ret; u16 dfl_disable_ss_mask = 0; lockdep_assert_held(&cgroup_mutex); @@ -1772,7 +1757,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) struct cgroup_root *src_root = ss->root; struct cgroup *scgrp = &src_root->cgrp; struct cgroup_subsys_state *css = cgroup_css(scgrp, ss); - struct css_set *cset; + struct css_set *cset, *cset_pos; + struct css_task_iter *it; WARN_ON(!css || cgroup_css(dcgrp, ss)); @@ -1790,10 +1776,21 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) css->cgroup = dcgrp; spin_lock_irq(&css_set_lock); - hash_for_each(css_set_table, i, cset, hlist) { - css_set_stop_iters(cset, ss); + WARN_ON(!list_empty(&dcgrp->e_csets[ss->id])); + list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id], + e_cset_node[ss->id]) { list_move_tail(&cset->e_cset_node[ss->id], &dcgrp->e_csets[ss->id]); + /* + * all css_sets of scgrp together in same order to dcgrp, + * patch in-flight iterators to preserve correct iteration. + * since the iterator is always advanced right away and + * finished when it->cset_pos meets it->cset_head, so only + * update it->cset_head is enough here. + */ + list_for_each_entry(it, &cset->task_iters, iters_node) + if (it->cset_head == &scgrp->e_csets[ss->id]) + it->cset_head = &dcgrp->e_csets[ss->id]; } spin_unlock_irq(&css_set_lock); @@ -4723,16 +4720,6 @@ static void css_task_iter_skip(struct css_task_iter *it, } } -static void css_task_iter_stop(struct css_task_iter *it, - struct cgroup_subsys *ss) -{ - lockdep_assert_held(&css_set_lock); - - if (it->ss == ss) { - it->flags |= CSS_TASK_ITER_STOPPED; - } -} - static void css_task_iter_advance(struct css_task_iter *it) { struct task_struct *task; @@ -4836,11 +4823,6 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it) spin_lock_irq(&css_set_lock); - if (it->flags & CSS_TASK_ITER_STOPPED) { - spin_unlock_irq(&css_set_lock); - return NULL; - } - /* @it may be half-advanced by skips, finish advancing */ if (it->flags & CSS_TASK_ITER_SKIPPED) css_task_iter_advance(it);