cgroup: prepare migration path for unified hierarchy

Unified hierarchy implementation would require re-migrating tasks onto
the same cgroup on the default hierarchy to reflect updated effective
csses.  Update cgroup_migrate_prepare_dst() so that it accepts NULL as
the destination cgrp.  When NULL is specified, the destination is
considered to be the cgroup on the default hierarchy associated with
each css_set.

After this change, the identity check in cgroup_migrate_add_src()
isn't sufficient for noop detection as the associated csses may change
without any cgroup association changing.  The only way to tell whether
a migration is noop or not is testing whether the source and
destination csets are identical.  The noop check in
cgroup_migrate_add_src() is removed and cset identity test is added to
cgroup_migreate_prepare_dst().  If it's detected that source and
destination csets are identical, the cset is removed removed from
@preloaded_csets and all the migration nodes are cleared which makes
cgroup_migrate() ignore the cset.

Also, make the function append the destination css_sets to
@preloaded_list so that destination css_sets always come after source
css_sets.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
Tejun Heo 2014-04-23 11:13:16 -04:00
parent 7fd8c565d8
commit f817de9851

View File

@ -1902,10 +1902,6 @@ static void cgroup_migrate_add_src(struct css_set *src_cset,
src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
/* nothing to do if this cset already belongs to the cgroup */
if (src_cgrp == dst_cgrp)
return;
if (!list_empty(&src_cset->mg_preload_node)) if (!list_empty(&src_cset->mg_preload_node))
return; return;
@ -1920,13 +1916,14 @@ static void cgroup_migrate_add_src(struct css_set *src_cset,
/** /**
* cgroup_migrate_prepare_dst - prepare destination css_sets for migration * cgroup_migrate_prepare_dst - prepare destination css_sets for migration
* @dst_cgrp: the destination cgroup * @dst_cgrp: the destination cgroup (may be %NULL)
* @preloaded_csets: list of preloaded source css_sets * @preloaded_csets: list of preloaded source css_sets
* *
* Tasks are about to be moved to @dst_cgrp and all the source css_sets * Tasks are about to be moved to @dst_cgrp and all the source css_sets
* have been preloaded to @preloaded_csets. This function looks up and * have been preloaded to @preloaded_csets. This function looks up and
* pins all destination css_sets, links each to its source, and put them on * pins all destination css_sets, links each to its source, and append them
* @preloaded_csets. * to @preloaded_csets. If @dst_cgrp is %NULL, the destination of each
* source css_set is assumed to be its cgroup on the default hierarchy.
* *
* This function must be called after cgroup_migrate_add_src() has been * This function must be called after cgroup_migrate_add_src() has been
* called on each migration source css_set. After migration is performed * called on each migration source css_set. After migration is performed
@ -1937,19 +1934,34 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp,
struct list_head *preloaded_csets) struct list_head *preloaded_csets)
{ {
LIST_HEAD(csets); LIST_HEAD(csets);
struct css_set *src_cset; struct css_set *src_cset, *tmp_cset;
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
/* look up the dst cset for each src cset and link it to src */ /* look up the dst cset for each src cset and link it to src */
list_for_each_entry(src_cset, preloaded_csets, mg_preload_node) { list_for_each_entry_safe(src_cset, tmp_cset, preloaded_csets, mg_preload_node) {
struct css_set *dst_cset; struct css_set *dst_cset;
dst_cset = find_css_set(src_cset, dst_cgrp); dst_cset = find_css_set(src_cset,
dst_cgrp ?: src_cset->dfl_cgrp);
if (!dst_cset) if (!dst_cset)
goto err; goto err;
WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset);
/*
* If src cset equals dst, it's noop. Drop the src.
* cgroup_migrate() will skip the cset too. Note that we
* can't handle src == dst as some nodes are used by both.
*/
if (src_cset == dst_cset) {
src_cset->mg_src_cgrp = NULL;
list_del_init(&src_cset->mg_preload_node);
put_css_set(src_cset, false);
put_css_set(dst_cset, false);
continue;
}
src_cset->mg_dst_cset = dst_cset; src_cset->mg_dst_cset = dst_cset;
if (list_empty(&dst_cset->mg_preload_node)) if (list_empty(&dst_cset->mg_preload_node))
@ -1958,7 +1970,7 @@ static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp,
put_css_set(dst_cset, false); put_css_set(dst_cset, false);
} }
list_splice(&csets, preloaded_csets); list_splice_tail(&csets, preloaded_csets);
return 0; return 0;
err: err:
cgroup_migrate_finish(&csets); cgroup_migrate_finish(&csets);