cgroup: call subsys->*attach() only for subsystems which are actually affected by migration
Currently, subsys->*attach() callbacks are called for all subsystems which are attached to the hierarchy on which the migration is taking place. With cgroup_migrate_prepare_dst() filtering out identity migrations, v1 hierarchies can avoid spurious ->*attach() callback invocations where the source and destination csses are identical; however, this isn't enough on v2 as only a subset of the attached controllers can be affected on controller enable/disable. While spurious ->*attach() invocations aren't critically broken, they're unnecessary overhead and can lead to temporary overcharges on certain controllers. Fix it by tracking which subsystems are affected by a migration and invoking ->*attach() callbacks only on those subsystems. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Zefan Li <lizefan@huawei.com>
This commit is contained in:
parent
e595cd7069
commit
bfc2cf6f61
|
@ -62,6 +62,9 @@ struct cgroup_mgctx {
|
||||||
|
|
||||||
/* tasks and csets to migrate */
|
/* tasks and csets to migrate */
|
||||||
struct cgroup_taskset tset;
|
struct cgroup_taskset tset;
|
||||||
|
|
||||||
|
/* subsystems affected by migration */
|
||||||
|
u16 ss_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CGROUP_TASKSET_INIT(tset) \
|
#define CGROUP_TASKSET_INIT(tset) \
|
||||||
|
@ -172,7 +175,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset, struct cgroup *dst_cgrp,
|
||||||
struct cgroup_mgctx *mgctx);
|
struct cgroup_mgctx *mgctx);
|
||||||
int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx);
|
int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx);
|
||||||
int cgroup_migrate(struct task_struct *leader, bool threadgroup,
|
int cgroup_migrate(struct task_struct *leader, bool threadgroup,
|
||||||
struct cgroup_mgctx *mgctx, struct cgroup_root *root);
|
struct cgroup_mgctx *mgctx);
|
||||||
|
|
||||||
int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader,
|
int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader,
|
||||||
bool threadgroup);
|
bool threadgroup);
|
||||||
|
|
|
@ -125,7 +125,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
|
||||||
css_task_iter_end(&it);
|
css_task_iter_end(&it);
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
ret = cgroup_migrate(task, false, &mgctx, to->root);
|
ret = cgroup_migrate(task, false, &mgctx);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
trace_cgroup_transfer_tasks(to, task, false);
|
trace_cgroup_transfer_tasks(to, task, false);
|
||||||
put_task_struct(task);
|
put_task_struct(task);
|
||||||
|
|
|
@ -2019,15 +2019,13 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset,
|
||||||
/**
|
/**
|
||||||
* cgroup_taskset_migrate - migrate a taskset
|
* cgroup_taskset_migrate - migrate a taskset
|
||||||
* @mgctx: migration context
|
* @mgctx: migration context
|
||||||
* @root: cgroup root the migration is taking place on
|
|
||||||
*
|
*
|
||||||
* Migrate tasks in @mgctx as setup by migration preparation functions.
|
* Migrate tasks in @mgctx as setup by migration preparation functions.
|
||||||
* This function fails iff one of the ->can_attach callbacks fails and
|
* This function fails iff one of the ->can_attach callbacks fails and
|
||||||
* guarantees that either all or none of the tasks in @mgctx are migrated.
|
* guarantees that either all or none of the tasks in @mgctx are migrated.
|
||||||
* @mgctx is consumed regardless of success.
|
* @mgctx is consumed regardless of success.
|
||||||
*/
|
*/
|
||||||
static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx,
|
static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
|
||||||
struct cgroup_root *root)
|
|
||||||
{
|
{
|
||||||
struct cgroup_taskset *tset = &mgctx->tset;
|
struct cgroup_taskset *tset = &mgctx->tset;
|
||||||
struct cgroup_subsys *ss;
|
struct cgroup_subsys *ss;
|
||||||
|
@ -2040,7 +2038,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* check that we can legitimately attach to the cgroup */
|
/* check that we can legitimately attach to the cgroup */
|
||||||
do_each_subsys_mask(ss, ssid, root->subsys_mask) {
|
do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
|
||||||
if (ss->can_attach) {
|
if (ss->can_attach) {
|
||||||
tset->ssid = ssid;
|
tset->ssid = ssid;
|
||||||
ret = ss->can_attach(tset);
|
ret = ss->can_attach(tset);
|
||||||
|
@ -2076,7 +2074,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx,
|
||||||
*/
|
*/
|
||||||
tset->csets = &tset->dst_csets;
|
tset->csets = &tset->dst_csets;
|
||||||
|
|
||||||
do_each_subsys_mask(ss, ssid, root->subsys_mask) {
|
do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
|
||||||
if (ss->attach) {
|
if (ss->attach) {
|
||||||
tset->ssid = ssid;
|
tset->ssid = ssid;
|
||||||
ss->attach(tset);
|
ss->attach(tset);
|
||||||
|
@ -2087,7 +2085,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx,
|
||||||
goto out_release_tset;
|
goto out_release_tset;
|
||||||
|
|
||||||
out_cancel_attach:
|
out_cancel_attach:
|
||||||
do_each_subsys_mask(ss, ssid, root->subsys_mask) {
|
do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
|
||||||
if (ssid == failed_ssid)
|
if (ssid == failed_ssid)
|
||||||
break;
|
break;
|
||||||
if (ss->cancel_attach) {
|
if (ss->cancel_attach) {
|
||||||
|
@ -2223,6 +2221,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
|
||||||
list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
|
list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
|
||||||
mg_preload_node) {
|
mg_preload_node) {
|
||||||
struct css_set *dst_cset;
|
struct css_set *dst_cset;
|
||||||
|
struct cgroup_subsys *ss;
|
||||||
|
int ssid;
|
||||||
|
|
||||||
dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp);
|
dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp);
|
||||||
if (!dst_cset)
|
if (!dst_cset)
|
||||||
|
@ -2251,6 +2251,10 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
|
||||||
&mgctx->preloaded_dst_csets);
|
&mgctx->preloaded_dst_csets);
|
||||||
else
|
else
|
||||||
put_css_set(dst_cset);
|
put_css_set(dst_cset);
|
||||||
|
|
||||||
|
for_each_subsys(ss, ssid)
|
||||||
|
if (src_cset->subsys[ssid] != dst_cset->subsys[ssid])
|
||||||
|
mgctx->ss_mask |= 1 << ssid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2263,7 +2267,6 @@ err:
|
||||||
* cgroup_migrate - migrate a process or task to a cgroup
|
* cgroup_migrate - migrate a process or task to a cgroup
|
||||||
* @leader: the leader of the process or the task to migrate
|
* @leader: the leader of the process or the task to migrate
|
||||||
* @threadgroup: whether @leader points to the whole process or a single task
|
* @threadgroup: whether @leader points to the whole process or a single task
|
||||||
* @root: cgroup root migration is taking place on
|
|
||||||
* @mgctx: migration context
|
* @mgctx: migration context
|
||||||
*
|
*
|
||||||
* Migrate a process or task denoted by @leader. If migrating a process,
|
* Migrate a process or task denoted by @leader. If migrating a process,
|
||||||
|
@ -2279,7 +2282,7 @@ err:
|
||||||
* actually starting migrating.
|
* actually starting migrating.
|
||||||
*/
|
*/
|
||||||
int cgroup_migrate(struct task_struct *leader, bool threadgroup,
|
int cgroup_migrate(struct task_struct *leader, bool threadgroup,
|
||||||
struct cgroup_mgctx *mgctx, struct cgroup_root *root)
|
struct cgroup_mgctx *mgctx)
|
||||||
{
|
{
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
|
|
||||||
|
@ -2299,7 +2302,7 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup,
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
spin_unlock_irq(&css_set_lock);
|
spin_unlock_irq(&css_set_lock);
|
||||||
|
|
||||||
return cgroup_migrate_execute(mgctx, root);
|
return cgroup_migrate_execute(mgctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2335,7 +2338,7 @@ int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader,
|
||||||
/* prepare dst csets and commit */
|
/* prepare dst csets and commit */
|
||||||
ret = cgroup_migrate_prepare_dst(&mgctx);
|
ret = cgroup_migrate_prepare_dst(&mgctx);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = cgroup_migrate(leader, threadgroup, &mgctx, dst_cgrp->root);
|
ret = cgroup_migrate(leader, threadgroup, &mgctx);
|
||||||
|
|
||||||
cgroup_migrate_finish(&mgctx);
|
cgroup_migrate_finish(&mgctx);
|
||||||
|
|
||||||
|
@ -2539,7 +2542,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&css_set_lock);
|
spin_unlock_irq(&css_set_lock);
|
||||||
|
|
||||||
ret = cgroup_migrate_execute(&mgctx, cgrp->root);
|
ret = cgroup_migrate_execute(&mgctx);
|
||||||
out_finish:
|
out_finish:
|
||||||
cgroup_migrate_finish(&mgctx);
|
cgroup_migrate_finish(&mgctx);
|
||||||
percpu_up_write(&cgroup_threadgroup_rwsem);
|
percpu_up_write(&cgroup_threadgroup_rwsem);
|
||||||
|
|
Loading…
Reference in New Issue