get_css_set(new_cset);
rcu_assign_pointer(tsk->cgroups, new_cset);
- list_move(&tsk->cg_list, &new_cset->mg_tasks);
+
+ /*
+ * Use move_tail so that cgroup_taskset_first() still returns the
+ * leader after migration. This works because cgroup_migrate()
+ * ensures that the dst_cset of the leader is the first on the
+ * tset's dst_csets list.
+ */
+ list_move_tail(&tsk->cg_list, &new_cset->mg_tasks);
/*
* We just gained a reference on old_cset by taking it from the
if (!cset->mg_src_cgrp)
goto next;
- list_move(&task->cg_list, &cset->mg_tasks);
- list_move(&cset->mg_node, &tset.src_csets);
- list_move(&cset->mg_dst_cset->mg_node, &tset.dst_csets);
+ /*
+ * cgroup_taskset_first() must always return the leader.
+ * Take care to avoid disturbing the ordering.
+ */
+ list_move_tail(&task->cg_list, &cset->mg_tasks);
+ if (list_empty(&cset->mg_node))
+ list_add_tail(&cset->mg_node, &tset.src_csets);
+ if (list_empty(&cset->mg_dst_cset->mg_node))
+ list_move_tail(&cset->mg_dst_cset->mg_node,
+ &tset.dst_csets);
next:
if (!threadgroup)
break;
down_write(&css_set_rwsem);
list_splice_init(&tset.dst_csets, &tset.src_csets);
list_for_each_entry_safe(cset, tmp_cset, &tset.src_csets, mg_node) {
- list_splice_init(&cset->mg_tasks, &cset->tasks);
+ list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
list_del_init(&cset->mg_node);
}
up_write(&css_set_rwsem);