diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 15261d74baa4aed19034e6a8938f9beb341ea1b3..6f0766ea159b3a98362892f731a1d3ce54eda8af 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -141,6 +141,9 @@ struct cgroup_subsys_state { */ int id; + /* number of tasks under this css and its descendants */ + int nr_tasks; + unsigned int flags; /* diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 474a23b1582209c9fd8110c7e6bd3adac4a45ead..237080ee3305cf140f66db07ac4cce872472f379 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1796,6 +1796,24 @@ static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) return 0; } +static void css_account_tasks(struct css_set *cset, int num) +{ + struct cgroup_subsys *ss; + int ssid; + + for_each_subsys(ss, ssid) { + struct cgroup_subsys_state *css = cset->subsys[ssid]; + + if (!css) + continue; + css->nr_tasks += num; + while (css->parent) { + css = css->parent; + css->nr_tasks += num; + } + } +} + /* * To reduce the fork() overhead for systems that are not actually using * their cgroups capability, we don't maintain the lists running through @@ -1847,6 +1865,7 @@ static void cgroup_enable_task_cg_lists(void) list_add_tail(&p->cg_list, &cset->tasks); get_css_set(cset); cset->nr_tasks++; + css_account_tasks(cset, 1); } spin_unlock(&p->sighand->siglock); } while_each_thread(g, p); @@ -2339,9 +2358,11 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx) get_css_set(to_cset); to_cset->nr_tasks++; + css_account_tasks(to_cset, 1); css_set_move_task(task, from_cset, to_cset, true); put_css_set_locked(from_cset); from_cset->nr_tasks--; + css_account_tasks(from_cset, -1); } } spin_unlock_irq(&css_set_lock); @@ -5828,6 +5849,7 @@ void cgroup_post_fork(struct task_struct *child) if (list_empty(&child->cg_list)) { get_css_set(cset); cset->nr_tasks++; + css_account_tasks(cset, 1); css_set_move_task(child, NULL, cset, false); } spin_unlock_irq(&css_set_lock); @@ -5879,6 +5901,7 @@ void cgroup_exit(struct task_struct *tsk) css_set_move_task(tsk, cset, NULL, false); list_add_tail(&tsk->cg_list, &cset->dying_tasks); cset->nr_tasks--; + css_account_tasks(cset, -1); spin_unlock_irq(&css_set_lock); } else { get_css_set(cset);