mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
cgroup fixes for v5.19-rc6
This pull request contains the fix for an old and subtle bug in the migration path. css_sets are used to track tasks and migrations are tasks moving from a group of css_sets to another group of css_sets. The migration path pins all source and destination css_sets in the prep stage. Unfortunately, it was overloading the same list_head entry to track sources and destinations, which got confused for migrations which are partially identity leading to use-after-frees. Fixed by using dedicated list_heads for tracking sources and destinations. -----BEGIN PGP SIGNATURE----- iIQEABYIACwWIQTfIjM1kS57o3GsC/uxYfJx3gVYGQUCYs48bg4cdGpAa2VybmVs Lm9yZwAKCRCxYfJx3gVYGb+HAQDNfUNLYajLjwJNklQdu/S4fxsg0qiY6J8SVkpo NYP2zQEAjZmBdNnW8MqutETBCwKq8v80gCphIT/Z72NNPStqPgQ= =r72j -----END PGP SIGNATURE----- Merge tag 'cgroup-for-5.19-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup Pull cgroup fix from Tejun Heo: "Fix an old and subtle bug in the migration path. css_sets are used to track tasks and migrations are tasks moving from a group of css_sets to another group of css_sets. The migration path pins all source and destination css_sets in the prep stage. Unfortunately, it was overloading the same list_head entry to track sources and destinations, which got confused for migrations which are partially identity leading to use-after-frees. Fixed by using dedicated list_heads for tracking sources and destinations" * tag 'cgroup-for-5.19-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup: Use separate src/dst nodes when preloading css_sets for migration
This commit is contained in:
commit
d0b97f3891
@ -264,7 +264,8 @@ struct css_set {
|
||||
* List of csets participating in the on-going migration either as
|
||||
* source or destination. Protected by cgroup_mutex.
|
||||
*/
|
||||
struct list_head mg_preload_node;
|
||||
struct list_head mg_src_preload_node;
|
||||
struct list_head mg_dst_preload_node;
|
||||
struct list_head mg_node;
|
||||
|
||||
/*
|
||||
|
@ -765,7 +765,8 @@ struct css_set init_css_set = {
|
||||
.task_iters = LIST_HEAD_INIT(init_css_set.task_iters),
|
||||
.threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets),
|
||||
.cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links),
|
||||
.mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node),
|
||||
.mg_src_preload_node = LIST_HEAD_INIT(init_css_set.mg_src_preload_node),
|
||||
.mg_dst_preload_node = LIST_HEAD_INIT(init_css_set.mg_dst_preload_node),
|
||||
.mg_node = LIST_HEAD_INIT(init_css_set.mg_node),
|
||||
|
||||
/*
|
||||
@ -1240,7 +1241,8 @@ static struct css_set *find_css_set(struct css_set *old_cset,
|
||||
INIT_LIST_HEAD(&cset->threaded_csets);
|
||||
INIT_HLIST_NODE(&cset->hlist);
|
||||
INIT_LIST_HEAD(&cset->cgrp_links);
|
||||
INIT_LIST_HEAD(&cset->mg_preload_node);
|
||||
INIT_LIST_HEAD(&cset->mg_src_preload_node);
|
||||
INIT_LIST_HEAD(&cset->mg_dst_preload_node);
|
||||
INIT_LIST_HEAD(&cset->mg_node);
|
||||
|
||||
/* Copy the set of subsystem state objects generated in
|
||||
@ -2597,21 +2599,27 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
|
||||
*/
|
||||
void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
|
||||
{
|
||||
LIST_HEAD(preloaded);
|
||||
struct css_set *cset, *tmp_cset;
|
||||
|
||||
lockdep_assert_held(&cgroup_mutex);
|
||||
|
||||
spin_lock_irq(&css_set_lock);
|
||||
|
||||
list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded);
|
||||
list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded);
|
||||
|
||||
list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) {
|
||||
list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
|
||||
mg_src_preload_node) {
|
||||
cset->mg_src_cgrp = NULL;
|
||||
cset->mg_dst_cgrp = NULL;
|
||||
cset->mg_dst_cset = NULL;
|
||||
list_del_init(&cset->mg_preload_node);
|
||||
list_del_init(&cset->mg_src_preload_node);
|
||||
put_css_set_locked(cset);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
|
||||
mg_dst_preload_node) {
|
||||
cset->mg_src_cgrp = NULL;
|
||||
cset->mg_dst_cgrp = NULL;
|
||||
cset->mg_dst_cset = NULL;
|
||||
list_del_init(&cset->mg_dst_preload_node);
|
||||
put_css_set_locked(cset);
|
||||
}
|
||||
|
||||
@ -2651,7 +2659,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
|
||||
if (src_cset->dead)
|
||||
return;
|
||||
|
||||
if (!list_empty(&src_cset->mg_preload_node))
|
||||
if (!list_empty(&src_cset->mg_src_preload_node))
|
||||
return;
|
||||
|
||||
src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
|
||||
@ -2664,7 +2672,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
|
||||
src_cset->mg_src_cgrp = src_cgrp;
|
||||
src_cset->mg_dst_cgrp = dst_cgrp;
|
||||
get_css_set(src_cset);
|
||||
list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets);
|
||||
list_add_tail(&src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2689,7 +2697,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
|
||||
|
||||
/* look up the dst cset for each src cset and link it to src */
|
||||
list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
|
||||
mg_preload_node) {
|
||||
mg_src_preload_node) {
|
||||
struct css_set *dst_cset;
|
||||
struct cgroup_subsys *ss;
|
||||
int ssid;
|
||||
@ -2708,7 +2716,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
|
||||
if (src_cset == dst_cset) {
|
||||
src_cset->mg_src_cgrp = NULL;
|
||||
src_cset->mg_dst_cgrp = NULL;
|
||||
list_del_init(&src_cset->mg_preload_node);
|
||||
list_del_init(&src_cset->mg_src_preload_node);
|
||||
put_css_set(src_cset);
|
||||
put_css_set(dst_cset);
|
||||
continue;
|
||||
@ -2716,8 +2724,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
|
||||
|
||||
src_cset->mg_dst_cset = dst_cset;
|
||||
|
||||
if (list_empty(&dst_cset->mg_preload_node))
|
||||
list_add_tail(&dst_cset->mg_preload_node,
|
||||
if (list_empty(&dst_cset->mg_dst_preload_node))
|
||||
list_add_tail(&dst_cset->mg_dst_preload_node,
|
||||
&mgctx->preloaded_dst_csets);
|
||||
else
|
||||
put_css_set(dst_cset);
|
||||
@ -2963,7 +2971,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
|
||||
goto out_finish;
|
||||
|
||||
spin_lock_irq(&css_set_lock);
|
||||
list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) {
|
||||
list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
|
||||
mg_src_preload_node) {
|
||||
struct task_struct *task, *ntask;
|
||||
|
||||
/* all tasks in src_csets need to be migrated */
|
||||
|
Loading…
Reference in New Issue
Block a user