cgroup: implement cgroup2 thread mode, v3
Subsystems (7)
Tejun Heo
maintainerPATCH 1/1 cgroup: implement cgroup2 thread mode, v3
Hello,
This is v3 of cgroup2 thread mode patchset. The changes from v2[L] are
* Switched to marking each cgroup threaded instead of doing it per-subtree as suggested by PeterZ. This allows more flexibility and removes certain interface quirks.
* Dropped RFC tag and excluded cpu controller patches from this patchset as threaded mode behaviors can easily be verified with the pid controller. Will follow up with cpu controller patchset later.
It is largely based on the discussions that we had at the plumbers last year. Here's the rough outline.
* Thread mode is explicitly enabled on a cgroup by writing "threaded" into "cgroup.type" file. The cgroup shouldn't have any processes or child cgroups. A threaded cgroup joins the the parent's resource domain and becomes a part of the threaded subtree anchored at the nearest domain ancestor, which is called the threaded domain cgroup of the subtree.
* Threads can be put anywhere in a threaded subtree by writing TIDs into "cgroup.threads" file. Process granularity and no-internal-process constraint don't apply in a threaded subtree.
* To be used in a threaded subtree, controllers should explicitly declare thread mode support and should be able to handle internal competition in some way.
* The threaded domain cgroup of a threaded subtree serves as the resource domain for the whole subtree. This is where all the controllers are guaranteed to have a common ground and resource consumptions in the threaded subtree which aren't tied to a specific thread are charged. Non-threaded controllers never see beyond thread root and can assume that all controllers will follow the same rules upto that point.
* Unlike other cgroups, the system root cgroup can serve as parent to domain child cgroups and threaded domains to threaded subtrees.
This allows threaded controllers to implement thread granular resource control without getting in the way of system level resource partitioning.
For more details on the interface and behavior, please refer to 0005.
This patchset contains the following six patches.
0001-cgroup-reorganize-cgroup.procs-task-write-path.patch 0002-cgroup-add-flags-to-css_task_iter_start-and-implemen.patch 0003-cgroup-introduce-cgroup-dom_cgrp-and-threaded-css_se.patch 0004-cgroup-implement-CSS_TASK_ITER_THREADED.patch 0005-cgroup-implement-cgroup-v2-thread-support.patch 0006-cgroup-update-debug-controller-to-print-out-thread-m.patch
0001-0005 implement cgroup2 thread mode. 0006 enables debug controller on it.
The patchset is based on the current cgroup/for-4.14 27f26753f8c0 ("cgroup: replace css_set walking populated test with testing cgrp->nr_populated_csets") and also available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-cgroup2-threads-v3
diffstat follows.
Documentation/cgroup-v2.txt | 181 +++++++++- include/linux/cgroup-defs.h | 45 ++ include/linux/cgroup.h | 15 kernel/cgroup/cgroup-internal.h | 12 kernel/cgroup/cgroup-v1.c | 69 +++ kernel/cgroup/cgroup.c | 712 +++++++++++++++++++++++++++++++--------- kernel/cgroup/cpuset.c | 6 kernel/cgroup/debug.c | 58 ++- kernel/cgroup/freezer.c | 6 kernel/cgroup/pids.c | 1 kernel/events/core.c | 1 mm/memcontrol.c | 2 net/core/netclassid_cgroup.c | 2 13 files changed, 906 insertions(+), 204 deletions(-)
Thanks.
--
tejun
[L] http://lkml.kernel.org/r/20170610140351.10703-1-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
Tejun Heo
maintainerPATCH 1/6 cgroup: reorganize cgroup.procs / task write path
Currently, writes "cgroup.procs" and "cgroup.tasks" files are all handled by __cgroup_procs_write() on both v1 and v2. This patch reoragnizes the write path so that there are common helper functions that different write paths use.
While this somewhat increases LOC, the different paths are no longer intertwined and each path has more flexibility to implement different behaviors which will be necessary for the planned v2 thread support.
v3: - Restructured so that cgroup_procs_write_permission() takes
@src_cgrp and @dst_cgrp.
v2: - Rolled in Waiman's task reference count fix.
- Updated on top of nsdelegate changes.
--- kernel/cgroup/cgroup-internal.h | 8 +- kernel/cgroup/cgroup-v1.c | 58 ++++++++++-- kernel/cgroup/cgroup.c | 192 ++++++++++++++++++++-------------------- 3 files changed, 152 insertions(+), 106 deletions(-)
kernel/cgroup/cgroup-internal.h +4 -4
@@ -180,10 +180,10 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup,int cgroup_attach_task (struct cgroup *dst_cgrp,struct task_struct *leader,bool threadgroup); -ssize_t __cgroup_procs_write (struct kernfs_open_file *of,char *buf, -size_t nbytes,loff_t off,bool threadgroup); -ssize_t cgroup_procs_write (struct kernfs_open_file *of,char *buf,size_t nbytes, -loff_t off); +struct task_struct *cgroup_procs_write_start (char *buf,bool threadgroup) + __acquires(&cgroup_threadgroup_rwsem); +void cgroup_procs_write_finish(struct task_struct *task) + __releases(&cgroup_threadgroup_rwsem);void cgroup_lock_and_drain_offline (struct cgroup *cgrp);
kernel/cgroup/cgroup-v1.c +53 -5
77 lines not on this page · raw message
kernel/cgroup/cgroup.c +95 -97
232 lines not on this page · raw message
Signature · 1 line
2.9.3
Tejun Heo
maintainerPATCH 2/6 cgroup: add @flags to css_task_iter_start() and implement CSS_TASK_ITER_PROCS
In reply to Tejun Heocss_task_iter currently always walks all tasks. With the scheduled cgroup v2 thread support, the iterator would need to handle multiple types of iteration. As a preparation, add @flags to css_task_iter_start() and implement CSS_TASK_ITER_PROCS. If the flag is not specified, it walks all tasks as before. When asserted, the iterator only walks the group leaders.
For now, the only user of the flag is cgroup v2 "cgroup.procs" file which no longer needs to skip non-leader tasks in cgroup_procs_next(). Note that cgroup v1 "cgroup.procs" can't use the group leader walk as v1 "cgroup.procs" doesn't mean "list all thread group leaders in the cgroup" but "list all thread group id's with any threads in the cgroup".
While at it, update cgroup_procs_show() to use task_pid_vnr() instead of task_tgid_vnr(). As the iteration guarantees that the function only sees group leaders, this doesn't change the output and will allow sharing the function for thread iteration.
--- include/linux/cgroup.h | 6 +++++- kernel/cgroup/cgroup-v1.c | 6 +++--- kernel/cgroup/cgroup.c | 24 ++++++++++++++---------- kernel/cgroup/cpuset.c | 6 +++--- kernel/cgroup/freezer.c | 6 +++--- mm/memcontrol.c | 2 +- net/core/netclassid_cgroup.c | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-)
include/linux/cgroup.h +5 -1
@@ -36,9 +36,13 @@#define CGROUP_WEIGHT_DFL 100#define CGROUP_WEIGHT_MAX 10000 +/* walk only threadgroup leaders */ +#define CSS_TASK_ITER_PROCS (1U << 0) +/* a css_task_iter should be treated as an opaque object */ struct css_task_iter {struct cgroup_subsys *ss; +unsigned int flags;struct list_head *cset_pos;struct list_head *cset_head;
@@ -129,7 +133,7 @@ struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,struct task_struct *cgroup_taskset_next (struct cgroup_taskset *tset,struct cgroup_subsys_state **dst_cssp); -void css_task_iter_start (struct cgroup_subsys_state *css, +void css_task_iter_start (struct cgroup_subsys_state *css,unsigned int flags,struct css_task_iter *it);struct task_struct *css_task_iter_next (struct css_task_iter *it);void css_task_iter_end (struct css_task_iter *it);
kernel/cgroup/cgroup-v1.c +3 -3
@@ -121,7 +121,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)* ->can_attach() fails. */ do { - css_task_iter_start(&from->self, &it); + css_task_iter_start(&from->self, 0, &it); task = css_task_iter_next(&it); if (task) get_task_struct(task);
@@ -373,7 +373,7 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,if (!array)return -ENOMEM ;/* now, populate the array */ -css_task_iter_start (&cgrp->self, &it); +css_task_iter_start (&cgrp->self,0 , &it);while ((tsk =css_task_iter_next (&it))) {if (unlikely (n == length))break ;
@@ -749,7 +749,7 @@ int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry) }rcu_read_unlock (); -css_task_iter_start (&cgrp->self, &it); +css_task_iter_start (&cgrp->self,0 , &it);while ((tsk =css_task_iter_next (&it))) {switch (tsk->state) {case TASK_RUNNING :
kernel/cgroup/cgroup.c +14 -10
@@ -3643,6 +3643,7 @@ static void css_task_iter_advance(struct css_task_iter *it)lockdep_assert_held (&css_set_lock);WARN_ON_ONCE (!l); +repeat:/* * Advance iterator to find next entry. cset->tasks is consumed * first and then ->mg_tasks. After ->mg_tasks, we move onto the
@@ -3657,11 +3658,18 @@ static void css_task_iter_advance(struct css_task_iter *it)css_task_iter_advance_css_set (it); else it->task_pos = l; + +/* if PROCS, skip over tasks which aren't group leaders */ +if ((it->flags &CSS_TASK_ITER_PROCS ) && it->task_pos && + !thread_group_leader(list_entry(it->task_pos, struct task_struct, + cg_list))) + goto repeat; }/** * css_task_iter_start - initiate task iteration * @css: the css to walk tasks of +* @flags: CSS_TASK_ITER_* flags * @it: the task iterator to use * * Initiate iteration through the tasks of @css. The caller can call
@@ -3669,7 +3677,7 @@ static void css_task_iter_advance(struct css_task_iter *it)* returns NULL. On completion of iteration, css_task_iter_end() must be * called. */ -void css_task_iter_start (struct cgroup_subsys_state *css, +void css_task_iter_start (struct cgroup_subsys_state *css,unsigned int flags,struct css_task_iter *it) {/* no one should try to iterate before mounting cgroups */
@@ -3680,6 +3688,7 @@ void css_task_iter_start(struct cgroup_subsys_state *css,spin_lock_irq (&css_set_lock); it->ss = css->ss; + it->flags = flags;if (it->ss) it->cset_pos = &css->cgroup->e_csets[css->ss->id];
@@ -3753,13 +3762,8 @@ static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos) {struct kernfs_open_file *of = s->private;struct css_task_iter *it = of->priv; -struct task_struct *task; - -do { - task =css_task_iter_next (it); - }while (task && !thread_group_leader (task)); -return task; +return css_task_iter_next (it); }static void *cgroup_procs_start (struct seq_file *s,loff_t *pos)
@@ -3780,10 +3784,10 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos)if (!it)return ERR_PTR (-ENOMEM ); of->priv = it; -css_task_iter_start (&cgrp->self, it); +css_task_iter_start (&cgrp->self,CSS_TASK_ITER_PROCS , it); }else if (!(*pos)++) {css_task_iter_end (it); -css_task_iter_start (&cgrp->self, it); +css_task_iter_start (&cgrp->self,CSS_TASK_ITER_PROCS , it); }return cgroup_procs_next (s,NULL ,NULL );
@@ -3791,7 +3795,7 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos)static int cgroup_procs_show (struct seq_file *s,void *v) { -seq_printf (s,"%d\n" ,task_tgid_vnr (v)); +seq_printf (s,"%d\n" ,task_pid_vnr (v));return 0 ; }
kernel/cgroup/cpuset.c +3 -3
@@ -861,7 +861,7 @@ static void update_tasks_cpumask(struct cpuset *cs)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it)))set_cpus_allowed_ptr (task, cs->effective_cpus);css_task_iter_end (&it);
@@ -1091,7 +1091,7 @@ static void update_tasks_nodemask(struct cpuset *cs)* It's ok if we rebind the same mm twice; mpol_rebind_mm() * is idempotent. Also migrate pages in each mm to new nodes. */ -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it))) {struct mm_struct *mm;bool migrate;
@@ -1284,7 +1284,7 @@ static void update_tasks_flags(struct cpuset *cs)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it)))cpuset_update_task_spread_flag (cs, task);css_task_iter_end (&it);
kernel/cgroup/freezer.c +3 -3
@@ -268,7 +268,7 @@ static void update_if_frozen(struct cgroup_subsys_state *css)rcu_read_unlock ();/* are all tasks frozen? */ -css_task_iter_start (css, &it); +css_task_iter_start (css,0 , &it);while ((task =css_task_iter_next (&it))) {if (freezing (task)) {
@@ -320,7 +320,7 @@ static void freeze_cgroup(struct freezer *freezer)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&freezer->css, &it); +css_task_iter_start (&freezer->css,0 , &it);while ((task =css_task_iter_next (&it)))freeze_task (task);css_task_iter_end (&it);
@@ -331,7 +331,7 @@ static void unfreeze_cgroup(struct freezer *freezer)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&freezer->css, &it); +css_task_iter_start (&freezer->css,0 , &it);while ((task =css_task_iter_next (&it)))__thaw_task (task);css_task_iter_end (&it);
mm/memcontrol.c +1 -1
@@ -917,7 +917,7 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&iter->css, &it); +css_task_iter_start (&iter->css,0 , &it);while (!ret && (task =css_task_iter_next (&it))) ret =fn (task, arg);css_task_iter_end (&it);
net/core/netclassid_cgroup.c +1 -1
@@ -100,7 +100,7 @@ static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, cs->classid = (u32 )value; -css_task_iter_start (css, &it); +css_task_iter_start (css,0 , &it);while ((p =css_task_iter_next (&it))) {task_lock (p); iterate_fd(p->files, 0, update_classid_sock,
Signature · 1 line
2.9.3
Tejun Heo
maintainerPATCH 3/6 cgroup: introduce cgroup->dom_cgrp and threaded css_set handling
In reply to Tejun Heocgroup v2 is in the process of growing thread granularity support. A threaded subtree is composed of a thread root and threaded cgroups which are proper members of the subtree.
The root cgroup of the subtree serves as the domain cgroup to which the processes (as opposed to threads / tasks) of the subtree conceptually belong and domain-level resource consumptions not tied to any specific task are charged. Inside the subtree, threads won't be subject to process granularity or no-internal-task constraint and can be distributed arbitrarily across the subtree.
This patch introduces cgroup->dom_cgrp along with threaded css_set handling.
* cgroup->dom_cgrp points to self for normal and thread roots. For proper thread subtree members, points to the dom_cgrp (the thread root).
* css_set->dom_cset points to self if for normal and thread roots. If threaded, points to the css_set which belongs to the cgrp->dom_cgrp. The dom_cgrp serves as the resource domain and keeps the matching csses available. The dom_cset holds those csses and makes them easily accessible.
* All threaded csets are linked on their dom_csets to enable iteration of all threaded tasks.
* cgroup->nr_threaded_children keeps track of the number of threaded children.
This patch adds the above but doesn't actually use them yet. The following patches will build on top.
v4: ->nr_threaded_children added.
v3: ->proc_cgrp/cset renamed to ->dom_cgrp/cset. Updated for the new
enable-threaded-per-cgroup behavior.
v2: Added cgroup_is_threaded() helper.
--- include/linux/cgroup-defs.h | 33 +++++++++++++++++++--- include/linux/cgroup.h | 3 +- kernel/cgroup/cgroup.c | 69 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 8 deletions(-)
include/linux/cgroup-defs.h +29 -4
@@ -172,6 +172,14 @@ struct css_set {/* reference count */ refcount_t refcount; +/* +* For a domain cgroup, the following points to self. If threaded, +* to the matching cset of the nearest domain ancestor. The +* dom_cset provides access to the domain cgroup and its csses to +* which domain level resource consumptions should be charged. +*/ +struct css_set *dom_cset; +/* the default cgroup associated with this css_set */ struct cgroup *dfl_cgrp;
@@ -200,6 +208,10 @@ struct css_set {*/ struct list_head e_cset_node[CGROUP_SUBSYS_COUNT ]; +/* all threaded csets whose ->dom_cset points to this cset */ +struct list_head threaded_csets; +struct list_head threaded_csets_node; +/* * List running through all cgroup groups in the same hash * slot. Protected by css_set_lock
@@ -267,12 +279,16 @@ struct cgroup {* doesn't have any tasks. * * All children which have non-zero nr_populated_csets and/or -* nr_populated_children of their own contribute one to -* nr_populated_children. The counter is zero iff this cgroup's -* subtree proper doesn't have any tasks. +* nr_populated_children of their own contribute one to either +* nr_populated_domain_children or nr_populated_threaded_children +* depending on their type. Each counter is zero iff all cgroups +* of the type in the subtree proper don't have any tasks. */ int nr_populated_csets; -int nr_populated_children; +int nr_populated_domain_children; +int nr_populated_threaded_children; + +int nr_threaded_children;/* # of live threaded child cgroups */ struct kernfs_node *kn;/* cgroup kernfs entry */ struct cgroup_file procs_file;/* handle for "cgroup.procs" */
@@ -311,6 +327,15 @@ struct cgroup {struct list_head e_csets[CGROUP_SUBSYS_COUNT ];/* +* If !threaded, self. If threaded, it points to the nearest +* domain ancestor. Inside a threaded subtree, cgroups are exempt +* from process granularity and no-internal-task constraint. +* Domain level resource consumptions which aren't tied to a +* specific task are charged to the dom_cgrp. +*/ +struct cgroup *dom_cgrp; + +/* * list of pidlists, up to two for each namespace (one for procs, one * for tasks); created on demand. */
include/linux/cgroup.h +2 -1
@@ -541,7 +541,8 @@ static inline bool task_under_cgroup_hierarchy(struct task_struct *task,/* no synchronization, the result can only be used as a hint */ static inline bool cgroup_is_populated (struct cgroup *cgrp) { -return cgrp->nr_populated_csets + cgrp->nr_populated_children; +return cgrp->nr_populated_csets + cgrp->nr_populated_domain_children + + cgrp->nr_populated_threaded_children; }/* returns ino associated with a cgroup */
kernel/cgroup/cgroup.c +66 -3
154 lines not on this page · raw message
Signature · 1 line
2.9.3
Tejun Heo
maintainerPATCH 4/6 cgroup: implement CSS_TASK_ITER_THREADED
In reply to Tejun Heocgroup v2 is in the process of growing thread granularity support. Once thread mode is enabled, the root cgroup of the subtree serves as the dom_cgrp to which the processes of the subtree conceptually belong and domain-level resource consumptions not tied to any specific task are charged. In the subtree, threads won't be subject to process granularity or no-internal-task constraint and can be distributed arbitrarily across the subtree.
This patch implements a new task iterator flag CSS_TASK_ITER_THREADED, which, when used on a dom_cgrp, makes the iteration include the tasks on all the associated threaded css_sets. "cgroup.procs" read path is updated to use it so that reading the file on a proc_cgrp lists all processes. This will also be used by controller implementations which need to walk processes or tasks at the resource domain level.
Task iteration is implemented nested in css_set iteration. If CSS_TASK_ITER_THREADED is specified, after walking tasks of each !threaded css_set, all the associated threaded css_sets are visited before moving onto the next !threaded css_set.
v2: ->cur_pcset renamed to ->cur_dcset. Updated for the new
enable-threaded-per-cgroup behavior.
--- include/linux/cgroup.h | 6 ++++ kernel/cgroup/cgroup.c | 77 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 17 deletions(-)
include/linux/cgroup.h +6 -0
@@ -38,6 +38,8 @@/* walk only threadgroup leaders */ #define CSS_TASK_ITER_PROCS (1U << 0) +/* walk all threaded css_sets in the domain */ +#define CSS_TASK_ITER_THREADED (1U << 1)/* a css_task_iter should be treated as an opaque object */ struct css_task_iter {
@@ -47,11 +49,15 @@ struct css_task_iter {struct list_head *cset_pos;struct list_head *cset_head; +struct list_head *tcset_pos; +struct list_head *tcset_head; +struct list_head *task_pos;struct list_head *tasks_head;struct list_head *mg_tasks_head;struct css_set *cur_cset; +struct css_set *cur_dcset;struct task_struct *cur_task;struct list_head iters_node;/* css_set->task_iters */ };
kernel/cgroup/cgroup.c +60 -17
120 lines not on this page · raw message
Signature · 1 line
2.9.3
Tejun Heo
maintainerPATCH 5/6 cgroup: implement cgroup v2 thread support
In reply to Tejun HeoThis patch implements cgroup v2 thread support. The goal of the thread mode is supporting hierarchical accounting and control at thread granularity while staying inside the resource domain model which allows coordination across different resource controllers and handling of anonymous resource consumptions.
A cgroup is always created as a domain and can be made threaded by writing to the "cgroup.type" file. When a cgroup becomes threaded, it becomes a member of a threaded subtree which is anchored at the closest ancestor which isn't threaded.
The threads of the processes which are in a threaded subtree can be placed anywhere without being restricted by process granularity or no-internal-process constraint. Note that the threads aren't allowed to escape to a different threaded subtree. To be used inside a threaded subtree, a controller should explicitly support threaded mode and be able to handle internal competition in the way which is appropriate for the resource.
The root of a threaded subtree, the nearest ancestor which isn't threaded, is called the threaded domain and serves as the resource domain for the whole subtree. This is the last cgroup where domain controllers are operational and where all the domain-level resource consumptions in the subtree are accounted. This allows threaded controllers to operate at thread granularity when requested while staying inside the scope of system-level resource distribution.
As the root cgroup is exempt from the no-internal-process constraint, it can serve as both a threaded domain and a parent to normal cgroups, so, unlike non-root cgroups, the root cgroup can have both domain and threaded children.
Internally, in a threaded subtree, each css_set has its ->dom_cset pointing to a matching css_set which belongs to the threaded domain. This ensures that thread root level cgroup_subsys_state for all threaded controllers are readily accessible for domain-level operations.
This patch enables threaded mode for the pids and perf_events controllers. Neither has to worry about domain-level resource consumptions and it's enough to simply set the flag.
For more details on the interface and behavior of the thread mode, please refer to the section 2-2-2 in Documentation/cgroup-v2.txt added by this patch.
v4: - Updated to marking each cgroup threaded as suggested by PeterZ.
v3: - Dropped "join" and always make mixed children join the parent's
threaded subtree.
v2: - After discussions with Waiman, support for mixed thread mode is
added. This should address the issue that Peter pointed out where any nesting should be avoided for thread subtrees while coexisting with other domain cgroups.
- Enabling / disabling thread mode now piggy backs on the existing control mask update mechanism.
- Bug fixes and cleanup.
--- Documentation/cgroup-v2.txt | 181 ++++++++++++++++++-- include/linux/cgroup-defs.h | 12 ++ kernel/cgroup/cgroup-internal.h | 2 +- kernel/cgroup/cgroup-v1.c | 5 +- kernel/cgroup/cgroup.c | 356 +++++++++++++++++++++++++++++++++++++--- kernel/cgroup/pids.c | 1 + kernel/events/core.c | 1 + 7 files changed, 518 insertions(+), 40 deletions(-)
Documentation/cgroup-v2.txt +166 -15
@@ -18,7 +18,9 @@ v1 is available under Documentation/cgroup-v1/. 1-2. What is cgroup? 2. Basic Operations 2-1. Mounting - 2-2. Organizing Processes + 2-2. Organizing Processes and Threads + 2-2-1. Processes + 2-2-2. Threads 2-3. [Un]populated Notification 2-4. Controlling Controllers 2-4-1. Enabling and Disabling
@@ -167,8 +169,11 @@ cgroup v2 currently supports the following mount options. Delegation section for details. -Organizing Processes --------------------- +Organizing Processes and Threads +-------------------------------- + +Processes +~~~~~~~~~ Initially, only the root cgroup exists to which all processes belong. A child cgroup can be created by creating a sub-directory::
@@ -219,6 +224,104 @@ If the process becomes a zombie and the cgroup it was associated with 0::/test-cgroup/test-cgroup-nested (deleted) +Threads +~~~~~~~ + +cgroup v2 supports thread granularity for a subset of controllers to +support use cases requiring hierarchical resource distribution across +the threads of a group of processes. By default, all threads of a +process belong to the same cgroup, which also serves as the resource +domain to host resource consumptions which are not specific to a +process or thread. The thread mode allows threads to be spread across +a subtree while still maintaining the common resource domain for them. + +Controllers which support thread mode are called threaded controllers. +The ones which don't are called domain controllers. + +Marking a cgroup threaded makes it join the resource domain of its +parent as a threaded cgroup. The parent may be another threaded +cgroup whose resource domain is further up in the hierarchy. The root +of a threaded subtree, that is, the nearest ancestor which is not +threaded, is called threaded domain and serves as the resource domain +for the entire subtree. + +Inside a threaded subtree, threads of a process can be put in +different cgroups and are not subject to the no internal process +constraint - threaded controllers can be enabled on non-leaf cgroups +whether they have threads in them or not. + +As the threaded domain cgroup hosts all the domain resource +consumptions of the subtree, it is considered to have internal +resource consumptions whether there are processes in it or not and +can't have populated child cgroups which aren't threaded. Because the +root cgroup is not subject to no internal process constraint, it can +serve both as a threaded domain and a parent to domain cgroups. + +The current operation mode or type of the cgroup is shown in the +"cgroup.type" file which indicates whether the cgroup is a normal +domain, a domain which is serving as the domain of a threaded subtree, +or a threaded cgroup. + +On creation, a cgroup is always a domain cgroup and can be made +threaded by writing "threaded" to the "cgroup.type" file. The +operation is single direction:: + + # echo threaded > cgroup.type + +Once threaded, the cgroup can't be made a domain again. To enable the +thread mode, the following conditions must be met. + +- As the cgroup will join the parent's resource domain. The parent + must either be a valid (threaded) domain or a threaded cgroup. + +- The cgroup must be empty. No enabled controllers, child cgroups or + processes. + +Topology-wise, a cgroup can be in an invalid state. Please consider +the following toplogy:: + + A (threaded domain) - B (threaded) - C (domain, just created) + +C is created as a domain but isn't connected to a parent which can +host child domains. C can't be used until it is turned into a +threaded cgroup. "cgroup.type" file will report "domain (invalid)" in +these cases. Operations which fail due to invalid topology use +EOPNOTSUPP as the errno. + +A domain cgroup is turned into a threaded domain when one of its child +cgroup becomes threaded or threaded controllers are enabled in the +"cgroup.subtree_control" file while there are processes in the cgroup. +A threaded domain reverts to a normal domain when the conditions +clear. + +When read, "cgroup.threads" contains the list of the thread IDs of all +threads in the cgroup. Except that the operations are per-thread +instead of per-process, "cgroup.threads" has the same format and +behaves the same way as "cgroup.procs". While "cgroup.threads" can be +written to in any cgroup, as it can only move threads inside the same +threaded domain, its operations are confined inside each threaded +subtree. + +The threaded domain cgroup serves as the resource domain for the whole +subtree, and, while the threads can be scattered across the subtree, +all the processes are considered to be in the threaded domain cgroup. +"cgroup.procs" in a threaded domain cgroup contains the PIDs of all +processes in the subtree and is not readable in the subtree proper. +However, "cgroup.procs" can be written to from anywhere in the subtree +to migrate all threads of the matching process to the cgroup. + +Only threaded controllers can be enabled in a threaded subtree. When +a threaded controller is enabled inside a threaded subtree, it only +accounts for and controls resource consumptions associated with the +threads in the cgroup and its descendants. All consumptions which +aren't tied to a specific thread belong to the threaded domain cgroup. + +Because a threaded subtree is exempt from no internal process +constraint, a threaded controller must be able to handle competition +between threads in a non-leaf cgroup and its child cgroups. Each +threaded controller defines how such competitions are handled. + + [Un]populated Notification --------------------------
@@ -302,15 +405,15 @@ disabled if one or more children have it enabled. No Internal Process Constraint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Non-root cgroups can only distribute resources to their children when -they don't have any processes of their own. In other words, only -cgroups which don't contain any processes can have controllers enabled -in their "cgroup.subtree_control" files. +Non-root cgroups can distribute domain resources to their children +only when they don't have any processes of their own. In other words, +only domain cgroups which don't contain any processes can have domain +controllers enabled in their "cgroup.subtree_control" files. -This guarantees that, when a controller is looking at the part of the -hierarchy which has it enabled, processes are always only on the -leaves. This rules out situations where child cgroups compete against -internal processes of the parent. +This guarantees that, when a domain controller is looking at the part +of the hierarchy which has it enabled, processes are always only on +the leaves. This rules out situations where child cgroups compete +against internal processes of the parent. The root cgroup is exempt from this restriction. Root contains processes and anonymous resource consumption which can't be associated
@@ -334,10 +437,10 @@ Model of Delegation ~~~~~~~~~~~~~~~~~~~ A cgroup can be delegated in two ways. First, to a less privileged -user by granting write access of the directory and its "cgroup.procs" -and "cgroup.subtree_control" files to the user. Second, if the -"nsdelegate" mount option is set, automatically to a cgroup namespace -on namespace creation. +user by granting write access of the directory and its "cgroup.procs", +"cgroup.threads" and "cgroup.subtree_control" files to the user. +Second, if the "nsdelegate" mount option is set, automatically to a +cgroup namespace on namespace creation. Because the resource control interface files in a given directory control the distribution of the parent's resources, the delegatee
@@ -644,6 +747,29 @@ Core Interface Files All cgroup core files are prefixed with "cgroup." + cgroup.type + + A read-write single value file which exists on non-root + cgroups. + + When read, it indicates the current type of the cgroup, which + can be one of the following values. + + - "domain" : A normal valid domain cgroup. + + - "domain (threaded)" : A threaded domain cgroup which is + serving as the root of a threaded subtree. + + - "domain (invalid)" : A cgroup which is in an invalid state. + It can't be populated or have controllers enabled. It may + be allowed to become a threaded cgroup. + + - "threaded" : A threaded cgroup which is a member of a + threaded subtree. + + A cgroup can be turned into a threaded cgroup by writing + "threaded" to this file. + cgroup.procs A read-write new-line separated values file which exists on all cgroups.
@@ -666,6 +792,31 @@ All cgroup core files are prefixed with "cgroup." When delegating a sub-hierarchy, write access to this file should be granted along with the containing directory. + cgroup.threads + A read-write new-line separated values file which exists on + all cgroups. + + When read, it lists the TIDs of all threads which belong to + the cgroup one-per-line. The TIDs are not ordered and the + same TID may show up more than once if the thread got moved to + another cgroup and then back or the TID got recycled while + reading. + + A TID can be written to migrate the thread associated with the + TID to the cgroup. The writer should match all of the + following conditions. + + - It must have write access to the "cgroup.threads" file. + + - The cgroup that the thread is currently in must be in the + same resource domain as the destination cgroup. + + - It must have write access to the "cgroup.procs" file of the + common ancestor of the source and destination cgroups. + + When delegating a sub-hierarchy, write access to this file + should be granted along with the containing directory. + cgroup.controllers A read-only space separated values file which exists on all cgroups.
include/linux/cgroup-defs.h +12 -0
@@ -522,6 +522,18 @@ struct cgroup_subsys { bool implicit_on_dfl:1;/* +* If %true, the controller, supports threaded mode on the default +* hierarchy. In a threaded subtree, both process granularity and +* no-internal-process constraint are ignored and a threaded +* controllers should be able to handle that. +* +* Note that as an implicit controller is automatically enabled on +* all cgroups on the default hierarchy, it should also be +* threaded. implicit && !threaded is not supported. +*/ + bool threaded:1; + +/* * If %false, this subsystem is properly hierarchical - * configuration, resource accounting and restriction on a parent * cgroup cover those of its children. If %true, hierarchy support
kernel/cgroup/cgroup-internal.h +1 -1
@@ -170,7 +170,7 @@ struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags, struct cgroup_root *root, unsigned long magic, struct cgroup_namespace *ns); -bool cgroup_may_migrate_to (struct cgroup *dst_cgrp); +int cgroup_migrate_vet_dst (struct cgroup *dst_cgrp);void cgroup_migrate_finish (struct cgroup_mgctx *mgctx);void cgroup_migrate_add_src (struct css_set *src_cset,struct cgroup *dst_cgrp,struct cgroup_mgctx *mgctx);
kernel/cgroup/cgroup-v1.c +3 -2
@@ -99,8 +99,9 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)if (cgroup_on_dfl (to))return -EINVAL ; -if (!cgroup_may_migrate_to (to)) -return -EBUSY ; + ret =cgroup_migrate_vet_dst (to); +if (ret) +return ret;mutex_lock (&cgroup_mutex);
kernel/cgroup/cgroup.c +334 -22
463 lines not on this page · raw message
kernel/cgroup/pids.c +1 -0
@@ -345,4 +345,5 @@ struct cgroup_subsys pids_cgrp_subsys = { .free = pids_free, .legacy_cftypes = pids_files, .dfl_cftypes = pids_files, + .threaded = true, };
kernel/events/core.c +1 -0
@@ -11210,5 +11210,6 @@ struct cgroup_subsys perf_event_cgrp_subsys = {* controller is not mounted on a legacy hierarchy. */ .implicit_on_dfl = true, + .threaded = true, };#endif /* CONFIG_CGROUP_PERF */
Signature · 1 line
2.9.3
Peter Zijlstra
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 25 lines · Tejun Heo
v4: - Updated to marking each cgroup threaded as suggested by PeterZ.
Documentation/cgroup-v2.txt +21
-0+On creation, a cgroup is always a domain cgroup and can be made +threaded by writing "threaded" to the "cgroup.type" file. The +operation is single direction:: + + # echo threaded > cgroup.type + +Once threaded, the cgroup can't be made a domain again. To enable the +thread mode, the following conditions must be met. + +- As the cgroup will join the parent's resource domain. The parent + must either be a valid (threaded) domain or a threaded cgroup. + +- The cgroup must be empty. No enabled controllers, child cgroups or + processes. + +Topology-wise, a cgroup can be in an invalid state. Please consider +the following toplogy:: + + A (threaded domain) - B (threaded) - C (domain, just created) + +C is created as a domain but isn't connected to a parent which can
Documentation/cgroup-v2.txt If the process becomes a zombie and the cgroup it was associated with · line 295
Quoted 10 lines
Documentation/cgroup-v2.txt +10
-0+host child domains. C can't be used until it is turned into a +threaded cgroup. "cgroup.type" file will report "domain (invalid)" in +these cases. Operations which fail due to invalid topology use +EOPNOTSUPP as the errno. + +A domain cgroup is turned into a threaded domain when one of its child +cgroup becomes threaded or threaded controllers are enabled in the +"cgroup.subtree_control" file while there are processes in the cgroup. +A threaded domain reverts to a normal domain when the conditions +clear.
AFAICT this is not in fact what I suggested... :/
My proposal did not have that invalid state. It would simply refuse to change the type from thread to domain in the case where the parent is not a domain.
Also, my proposal maintained the normal property inheritance rules. A child cgroup's creation 'type' would be that of its parent and not always be 'domain'.
Let me read more (and more careful) to see if there's other things.
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello, Peter.
Quoted 1 line · Peter Zijlstra
AFAICT this is not in fact what I suggested... :/
Heh, sorry about misattributing that. I was mostly referring to the overall idea of marking each cgroup domain or threaded rather than subtree.
Quoted 7 lines
My proposal did not have that invalid state. It would simply refuse to change the type from thread to domain in the case where the parent is not a domain.
Also, my proposal maintained the normal property inheritance rules. A child cgroup's creation 'type' would be that of its parent and not always be 'domain'.
But aren't both of the above get weird when the parent can host both domain and threaded children?
R
/
A(D)If you create another child B under R, it's naturally gonna be a domain. Let's say you turn that to threaded.
R
/ \
A(D) B(T)And now try to create another child C, should that be a domain or threaded?
If we only inherit from the second level on, which is in itself already confusing, that still leads to invalid configs for non-root thread roots.
I don't think whether we fail the transition or put the cgroup in an invalid state is all that material. The simpler the better.
Quoted 1 line
Let me read more (and more careful) to see if there's other things.
Sure thing.
Thanks!
Signature · 1 line
tejun
Peter Zijlstra
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 27 lines · Tejun Heo
Hello, Peter.
Quoted 1 line · Peter Zijlstra
AFAICT this is not in fact what I suggested... :/
Heh, sorry about misattributing that. I was mostly referring to the overall idea of marking each cgroup domain or threaded rather than subtree.
Quoted 7 lines
My proposal did not have that invalid state. It would simply refuse to change the type from thread to domain in the case where the parent is not a domain.
Also, my proposal maintained the normal property inheritance rules. A child cgroup's creation 'type' would be that of its parent and not always be 'domain'.
But aren't both of the above get weird when the parent can host both domain and threaded children?
R / A(D)If you create another child B under R, it's naturally gonna be a domain. Let's say you turn that to threaded.
Quoted 6 lines
R / \ A(D) B(T)And now try to create another child C, should that be a domain or threaded?
Domain of course, as R must be a domain, and hence all its children start out as such.
Quoted 3 lines
If we only inherit from the second level on, which is in itself already confusing, that still leads to invalid configs for non-root thread roots.
I don't see how. I don't get the example Waiman gave, what is wrong with:
R (D)
|
A (D)
/ \
C(D) B(T) ? Afaict that's a perfectly valid configuration.
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 41 lines · Peter Zijlstra
Quoted 25 lines · Tejun Heo
Hello, Peter.
Quoted 1 line · Peter Zijlstra
AFAICT this is not in fact what I suggested... :/
Heh, sorry about misattributing that. I was mostly referring to the overall idea of marking each cgroup domain or threaded rather than subtree.
Quoted 7 lines
My proposal did not have that invalid state. It would simply refuse to change the type from thread to domain in the case where the parent is not a domain.
Also, my proposal maintained the normal property inheritance rules. A child cgroup's creation 'type' would be that of its parent and not always be 'domain'.
But aren't both of the above get weird when the parent can host both domain and threaded children?
R / A(D)If you create another child B under R, it's naturally gonna be a domain. Let's say you turn that to threaded.
Quoted 6 lines
R / \ A(D) B(T)And now try to create another child C, should that be a domain or threaded?
Domain of course, as R must be a domain, and hence all its children start out as such.
Quoted 3 lines
If we only inherit from the second level on, which is in itself already confusing, that still leads to invalid configs for non-root thread roots.
I don't see how. I don't get the example Waiman gave, what is wrong with:
Quoted 7 lines
R (D) | A (D) / \ C(D) B(T)? Afaict that's a perfectly valid configuration.
From what I understand, C is considered to be in an invalid state because of the no internal process rule. A in this case is the thread root, so it can have internal process. If C is a domain and a child of A, we will have the case that internal processes in A is competing against cgroup C.
I have been advocating (in one of my RFC patches) that we should relax the rules to allow internal processes when only threaded controllers are enabled as they are supposed to be able to handle internal processes.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
In reply to Peter ZijlstraHello, Peter.
Quoted 5 lines · Peter Zijlstra
Quoted 2 lines
And now try to create another child C, should that be a domain or threaded?
Domain of course, as R must be a domain, and hence all its children start out as such.
I don't think it's a matter of course as R also is the root of a threaded subtree, but this is more or less bikeshedding.
Quoted 7 lines
Quoted 3 lines
If we only inherit from the second level on, which is in itself already confusing, that still leads to invalid configs for non-root thread roots.
I don't see how. I don't get the example Waiman gave, what is wrong with:
Quoted 7 lines
R (D) | A (D) / \ C(D) B(T)? Afaict that's a perfectly valid configuration.
Okay, we're kinda off the rails now. Just to verify that we're on the same page, are you also saying that the following should be a valid configuration?
R (D)
|
A (D and has processes in it and controllers enabled)
|
C (D and has processes in it) Thanks.
Signature · 1 line
tejun
Peter Zijlstra
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 10 lines · Tejun Heo
Okay, we're kinda off the rails now. Just to verify that we're on the same page, are you also saying that the following should be a valid configuration?
R (D) | A (D and has processes in it and controllers enabled) | C (D and has processes in it)
Argh, the no internal process thing again -- I completely forgot about that :-(
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 13 lines · Peter Zijlstra
Quoted 10 lines · Tejun Heo
Okay, we're kinda off the rails now. Just to verify that we're on the same page, are you also saying that the following should be a valid configuration?
R (D) | A (D and has processes in it and controllers enabled) | C (D and has processes in it)
Quoted 2 lines
Argh, the no internal process thing again -- I completely forgot about that :-(
Heh, yeah, we wouldn't be talking about all these otherwise. The restriction is pain in the ass but at the same time useful for full(er)-scope resource control. Were there other things that caught your eyes?
Thanks.
Signature · 1 line
tejun
Peter Zijlstra
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 1 line · Tejun Heo
Were there other things that caught your eyes?
I didn't immediately see the point of "domain (threaded" output, and I think it might be useful to have a "threaded" column in /proc/cgroups. But no, I've been over this a few times now and I think we're good.
Yes, I think we can work with this. Thanks!
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello, Peter.
Quoted 4 lines · Peter Zijlstra
Quoted 1 line · Tejun Heo
Were there other things that caught your eyes?
I didn't immediately see the point of "domain (threaded" output, and I
I'll probably drop the parens but I think it's meaningful to show the state to userland as it affects what users can and can't do.
Quoted 1 line
think it might be useful to have a "threaded" column in
/proc/cgroups.
Will add that. We *might* want cgroup.controllers_threaded too but we can think about that later.
Quoted 3 lines
But no, I've been over this a few times now and I think we're good.
Yes, I think we can work with this. Thanks!
Awesome. I'll update the patchset.
Thanks a lot for the inputs and patience!
Signature · 1 line
tejun
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
In reply to Peter ZijlstraQuoted 36 lines · Peter Zijlstra
Quoted 23 lines · Tejun Heo
v4: - Updated to marking each cgroup threaded as suggested by PeterZ.
Documentation/cgroup-v2.txt +21
-0+On creation, a cgroup is always a domain cgroup and can be made +threaded by writing "threaded" to the "cgroup.type" file. The +operation is single direction:: + + # echo threaded > cgroup.type + +Once threaded, the cgroup can't be made a domain again. To enable the +thread mode, the following conditions must be met. + +- As the cgroup will join the parent's resource domain. The parent + must either be a valid (threaded) domain or a threaded cgroup. + +- The cgroup must be empty. No enabled controllers, child cgroups or + processes. + +Topology-wise, a cgroup can be in an invalid state. Please consider +the following toplogy:: + + A (threaded domain) - B (threaded) - C (domain, just created) + +C is created as a domain but isn't connected to a parent which canDocumentation/cgroup-v2.txt If the process becomes a zombie and the cgroup it was associated with · line 295
Quoted 10 lines
Documentation/cgroup-v2.txt +10
-0+host child domains. C can't be used until it is turned into a +threaded cgroup. "cgroup.type" file will report "domain (invalid)" in +these cases. Operations which fail due to invalid topology use +EOPNOTSUPP as the errno. + +A domain cgroup is turned into a threaded domain when one of its child +cgroup becomes threaded or threaded controllers are enabled in the +"cgroup.subtree_control" file while there are processes in the cgroup. +A threaded domain reverts to a normal domain when the conditions +clear.AFAICT this is not in fact what I suggested... :/
Quoted 7 lines
My proposal did not have that invalid state. It would simply refuse to change the type from thread to domain in the case where the parent is not a domain.
Also, my proposal maintained the normal property inheritance rules. A child cgroup's creation 'type' would be that of its parent and not always be 'domain'.
I agree with Peter on this. A new cgroup created under a threaded cgroup should always be threaded. I don't see a need for an intermediate invalid domain.
Cheers,
Longman
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 16 lines · Waiman Long
Quoted 15 lines · Peter Zijlstra
Quoted 14 lines · Tejun Heo
v4: - Updated to marking each cgroup threaded as suggested by PeterZ.
Documentation/cgroup-v2.txt +12
-0+On creation, a cgroup is always a domain cgroup and can be made +threaded by writing "threaded" to the "cgroup.type" file. The +operation is single direction:: + + # echo threaded > cgroup.type + +Once threaded, the cgroup can't be made a domain again. To enable the +thread mode, the following conditions must be met. + +- As the cgroup will join the parent's resource domain. The parent + must either be a valid (threaded) domain or a threaded cgroup. +
Quoted 8 lines
Quoted 8 lines
Documentation/cgroup-v2.txt If the process becomes a zombie and the cgroup it was associated with · line 284
Quoted 8 lines
+- The cgroup must be empty. No enabled controllers, child cgroups or
Documentation/cgroup-v2.txt +7
-0+ processes. + +Topology-wise, a cgroup can be in an invalid state. Please consider +the following toplogy:: + + A (threaded domain) - B (threaded) - C (domain, just created) +
Thinking about it some more. There is a place for invalid domain. It is not the child of a threaded cgroup. It is the siblings of a threaded cgroup whose parent is not root.
Root - A (domain) - B (domain)
\ C (domain)
With "echo threaded > B/cgroup.type":
Root - A (threaded domain) - B (threaded)
\ C (domain, invalid)
Any children of a threaded cgroup should be threaded.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello, Waiman.
Quoted 11 lines · Waiman Long
Thinking about it some more. There is a place for invalid domain. It is not the child of a threaded cgroup. It is the siblings of a threaded cgroup whose parent is not root.
Root - A (domain) - B (domain)
\ C (domain)With "echo threaded > B/cgroup.type":
Root - A (threaded domain) - B (threaded)
\ C (domain, invalid)
Yes, I noted that when I was replying to Peter.
Quoted 1 line
Any children of a threaded cgroup should be threaded.
It's really difficult to discuss if you just declare that something should be a certain way without giving rationale for thinking so.
If we could get rid of the invalid state completely that way, I'd completely agree with you but that isn't the case here as you noted yourself, so the choice between the two isn't something trivially clear. Both choices come with their pros and cons. We can absoultely discuss them comparing the pros and cons.
Thanks.
Signature · 1 line
tejun
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 17 lines · Tejun Heo
Hello, Waiman.
Quoted 11 lines · Waiman Long
Thinking about it some more. There is a place for invalid domain. It is not the child of a threaded cgroup. It is the siblings of a threaded cgroup whose parent is not root.
Root - A (domain) - B (domain)
\ C (domain)With "echo threaded > B/cgroup.type":
Root - A (threaded domain) - B (threaded)
\ C (domain, invalid)Yes, I noted that when I was replying to Peter.
Quoted 1 line
Any children of a threaded cgroup should be threaded.
Quoted 8 lines
It's really difficult to discuss if you just declare that something should be a certain way without giving rationale for thinking so.
If we could get rid of the invalid state completely that way, I'd completely agree with you but that isn't the case here as you noted yourself, so the choice between the two isn't something trivially clear. Both choices come with their pros and cons. We can absoultely discuss them comparing the pros and cons.
I am not advocating on removing the invalid state now as I note about sibling cgroups. I am just saying that there is no point in not doing an automatic conversion to threaded for newly created children of threaded cgroups (not thread root). I don't see any cons in doing that.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello,
Quoted 7 lines · Waiman Long
Quoted 5 lines
If we could get rid of the invalid state completely that way, I'd completely agree with you but that isn't the case here as you noted yourself, so the choice between the two isn't something trivially clear. Both choices come with their pros and cons. We can absoultely discuss them comparing the pros and cons.
I am not advocating on removing the invalid state now as I note about
Yeah, removing invalid state would be great but we can't at least yet.
Quoted 3 lines
sibling cgroups. I am just saying that there is no point in not doing an automatic conversion to threaded for newly created children of threaded cgroups (not thread root). I don't see any cons in doing that.
So, the cons I see is inconsistency, now and in the future.
This may seem less clear with system root because we can have both domain and theraded children below it, which makes a newly created cgroup being a domain seem natural. More importantly, we can't do it any other way because we'd break existing users otherwise - creating a threaded cgroup would cause future first level cgroups to be threaded which will be very unexpected.
Let's think about a non-root threaded domain. At least for now, a non-root threaded domain is terminal - they can't host valid domain children. As the alternative term "thread root" implies, the threaded domain can be the root of a threaded subtree and nothing else, so it's kinda weird to make a new child cgroup there start out as a domain which can't be used, just like it'd be for the second level descendant cgroup.
However, the alternative is even stranger. Let's say we make the first level child automatically threaded, but that is inconsistent with when we first enable threaded mode. We either would have to turn all siblings at the same time or disallow enabling threaded mode if there are domain siblings, which I fear would be unnecessarily restrictive.
Another point is that what if we eventually make non-root threaded roots able to host domain children? Making children automatically threaded wouldn't make any sense then, right? I'll come back to this later.
So, it looks like if we're gonna automatically turn on threaded mode for new cgroups, the only thing we can do right now is what you're suggesting; however, we didn't arrive there through some straight-forward intuition or overall design. It started as a simple idea (I want it to be automatic) but the end result is a contorted destination shaped by constraints and happenstance.
To me, behaving differently on the first-level threaded children than on second+ level ones is too strange to be justified by the convenience of not having to turn on threaded on new cgroups.
On top of that, what happens if we get to implement PeterZ's idea of skipping over threaded internal cgroups to allow domains under threaded subtrees? That'd imply that we'd be able to host domains under threaded domains too. The end result would be completely non-sensical. We'd be defaulting to different modes for different reasons where half of those reasons won't hold anymore. This isn't surprising given that there's nothing actually consistent about the suggested default behavior.
So, that's why I think it'd be better to be simple here, even if that adds a bit of hassle when creating threded children. It is simple and consistent and can stay that way even if we make the hierarchy more flexible in the future.
Thanks.
Signature · 1 line
tejun
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Quoted 50 lines · Tejun Heo
Hello,
Quoted 6 lines · Waiman Long
Quoted 5 lines
If we could get rid of the invalid state completely that way, I'd completely agree with you but that isn't the case here as you noted yourself, so the choice between the two isn't something trivially clear. Both choices come with their pros and cons. We can absoultely discuss them comparing the pros and cons.
I am not advocating on removing the invalid state now as I note about
Yeah, removing invalid state would be great but we can't at least yet.
Quoted 3 lines
sibling cgroups. I am just saying that there is no point in not doing an automatic conversion to threaded for newly created children of threaded cgroups (not thread root). I don't see any cons in doing that.
So, the cons I see is inconsistency, now and in the future.
This may seem less clear with system root because we can have both domain and theraded children below it, which makes a newly created cgroup being a domain seem natural. More importantly, we can't do it any other way because we'd break existing users otherwise - creating a threaded cgroup would cause future first level cgroups to be threaded which will be very unexpected.
Let's think about a non-root threaded domain. At least for now, a non-root threaded domain is terminal - they can't host valid domain children. As the alternative term "thread root" implies, the threaded domain can be the root of a threaded subtree and nothing else, so it's kinda weird to make a new child cgroup there start out as a domain which can't be used, just like it'd be for the second level descendant cgroup.
However, the alternative is even stranger. Let's say we make the first level child automatically threaded, but that is inconsistent with when we first enable threaded mode. We either would have to turn all siblings at the same time or disallow enabling threaded mode if there are domain siblings, which I fear would be unnecessarily restrictive.
Another point is that what if we eventually make non-root threaded roots able to host domain children? Making children automatically threaded wouldn't make any sense then, right? I'll come back to this later.
So, it looks like if we're gonna automatically turn on threaded mode for new cgroups, the only thing we can do right now is what you're suggesting; however, we didn't arrive there through some straight-forward intuition or overall design. It started as a simple idea (I want it to be automatic) but the end result is a contorted destination shaped by constraints and happenstance.
Quoted 3 lines
To me, behaving differently on the first-level threaded children than on second+ level ones is too strange to be justified by the convenience of not having to turn on threaded on new cgroups.
OK, I get your point of being inconsistent. However, I don't think that is a big deal.
Quoted 8 lines
On top of that, what happens if we get to implement PeterZ's idea of skipping over threaded internal cgroups to allow domains under threaded subtrees? That'd imply that we'd be able to host domains under threaded domains too. The end result would be completely non-sensical. We'd be defaulting to different modes for different reasons where half of those reasons won't hold anymore. This isn't surprising given that there's nothing actually consistent about the suggested default behavior.
For me, that is the only good reason why we should keep the current behavior. So I am fine with that.
+ cgrp->dom_cgrp = cgrp->dom_cgrp;
However, I am still puzzled by above line of code, should it be just
cgrp->dom_cgrp = cgrp;
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello, Waiman.
Quoted 8 lines · Waiman Long
For me, that is the only good reason why we should keep the current behavior. So I am fine with that.
+
cgrp->dom_cgrp=cgrp->dom_cgrp;However, I am still puzzled by above line of code, should it be just
cgrp->dom_cgrp = cgrp;
Oh I see. Yeah, that's just a silly (harmless) bug. The field gets properly initialized in init_cgroup_housekeeping(). I'll remove that line.
Thanks!
Signature · 1 line
tejun
Waiman Long
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
In reply to Tejun HeoQuoted 11 lines · Tejun Heo
Documentation/cgroup-v2.txt +10
-0+Threads +~~~~~~~ + +cgroup v2 supports thread granularity for a subset of controllers to +support use cases requiring hierarchical resource distribution across +the threads of a group of processes. By default, all threads of a +process belong to the same cgroup, which also serves as the resource +domain to host resource consumptions which are not specific to a +process or thread. The thread mode allows threads to be spread across +a subtree while still maintaining the common resource domain for them.
Documentation/cgroup-v2.txt If the process becomes a zombie and the cgroup it was associated with · line 246
Quoted 10 lines
Documentation/cgroup-v2.txt +10
-0+ +Controllers which support thread mode are called threaded controllers. +The ones which don't are called domain controllers. + +Marking a cgroup threaded makes it join the resource domain of its +parent as a threaded cgroup. The parent may be another threaded +cgroup whose resource domain is further up in the hierarchy. The root +of a threaded subtree, that is, the nearest ancestor which is not +threaded, is called threaded domain and serves as the resource domain +for the entire subtree.
The cgroup code uses the term "thread root" in quite a number of places. So a developer may be confused when comparing the code and the documentation. I would recommend either introducing "thread root" as an alias for threaded domain here in the documentation or documenting that "threaded domain = thread root" in the code.
Quoted 16 lines
Documentation/cgroup-v2.txt +16
-0+ cgroup.type + + A read-write single value file which exists on non-root + cgroups. + + When read, it indicates the current type of the cgroup, which + can be one of the following values. + + - "domain" : A normal valid domain cgroup. + + - "domain (threaded)" : A threaded domain cgroup which is + serving as the root of a threaded subtree. + + - "domain (invalid)" : A cgroup which is in an invalid state. + It can't be populated or have controllers enabled. It may + be allowed to become a threaded cgroup.
Documentation/cgroup-v2.txt Core Interface Files · line 775
Quoted 10 lines
Documentation/cgroup-v2.txt +7
-0+ + - "threaded" : A threaded cgroup which is a member of a + threaded subtree. + + A cgroup can be turned into a threaded cgroup by writing + "threaded" to this file. + cgroup.procs A read-write new-line separated values file which exists on all cgroups.
Do we need to document that cgroup.procs isn't writable in a threaded cgroup?
kernel/cgroup/cgroup.c static struct cgroup *cgroup_create(struct cgroup *parent) · line 4609
Quoted 5 lines
kernel/cgroup/cgroup.c +1
-0@@ -4301,6 +4606,7 @@ static struct cgroup *cgroup_create(struct cgroup *parent) cgrp->self.parent = &parent->self; cgrp->root = root; cgrp->level = level; + cgrp->dom_cgrp = cgrp->dom_cgrp;
It is a no-op. I think it is better to modify it to
+ cgrp->dom_cgrp = cgroup_is_threaded(parent) ? parent->dom_cgrp : cgrp;
Then we won't have an invalid domain state.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 5/6] cgroup: implement cgroup v2 thread support
Hello, Waiman.
Quoted 4 lines · Waiman Long
Quoted 4 lines
Documentation/cgroup-v2.txt +4
-0+Marking a cgroup threaded makes it join the resource domain of its +parent as a threaded cgroup. The parent may be another threaded +cgroup whose resource domain is further up in the hierarchy. The root +of a threaded subtree, that is, the nearest ancestor which is not
Quoted 8 lines
Documentation/cgroup-v2.txt If the process becomes a zombie and the cgroup it was associated with · line 246
Quoted 2 lines
Documentation/cgroup-v2.txt +2
-0+threaded, is called threaded domain and serves as the resource domain +for the entire subtree.The cgroup code uses the term "thread root" in quite a number of places. So a developer may be confused when comparing the code and the documentation. I would recommend either introducing "thread root" as an alias for threaded domain here in the documentation or documenting that "threaded domain = thread root" in the code.
Yeah, I was a bit hesitant to introduce an extra term for it, but both terms make sense and thread root is less cumbersome. I'll incorporate it into the doc.
Quoted 6 lines
Documentation/cgroup-v2.txt Core Interface Files · line 775
Quoted 3 lines
cgroup.procs
Documentation/cgroup-v2.txt +0
-0A read-write new-line separated values file which exists on all cgroups.Do we need to document that cgroup.procs isn't writable in a threaded cgroup?
Yeah, will update.
Quoted 11 lines
kernel/cgroup/cgroup.c static struct cgroup *cgroup_create(struct cgroup *parent) · line 4609
Quoted 5 lines
kernel/cgroup/cgroup.c +1
-0@@ -4301,6 +4606,7 @@ static struct cgroup *cgroup_create(struct cgroup *parent) cgrp->self.parent = &parent->self; cgrp->root = root; cgrp->level = level; + cgrp->dom_cgrp = cgrp->dom_cgrp;It is a no-op. I think it is better to modify it to
+
cgrp->dom_cgrp=cgroup_is_threaded(parent)?parent->dom_cgrp: cgrp;Then we won't have an invalid domain state.
I'll respond to this on the other sub-thread.
Thanks.
Signature · 1 line
tejun
Tejun Heo
maintainerPATCH 6/6 cgroup: update debug controller to print out thread mode information
In reply to Tejun HeoFrom: Waiman Long <[email protected]>
Update debug controller so that it prints out debug info about thread mode.
1) The relationship between proc_cset and threaded_csets are displayed.
2) The status of being a thread root or threaded cgroup is displayed.
This patch is extracted from Waiman's larger patch.
--- kernel/cgroup/cgroup-internal.h | 2 ++ kernel/cgroup/cgroup.c | 4 +-- kernel/cgroup/debug.c | 58 +++++++++++++++++++++++++++++++---------- 3 files changed, 48 insertions(+), 16 deletions(-)
kernel/cgroup/cgroup-internal.h +2 -0
@@ -153,6 +153,8 @@ static inline void get_css_set(struct css_set *cset)bool cgroup_ssid_enabled (int ssid);bool cgroup_on_dfl (const struct cgroup *cgrp); +bool cgroup_is_thread_root (struct cgroup *cgrp); +bool cgroup_is_threaded (struct cgroup *cgrp);struct cgroup_root *cgroup_root_from_kf (struct kernfs_root *kf_root); struct cgroup *task_cgroup_from_root(struct task_struct *task,
kernel/cgroup/cgroup.c +2 -2
@@ -333,7 +333,7 @@ static bool cgroup_has_tasks(struct cgroup *cgrp)return cgrp->nr_populated_csets; } -static bool cgroup_is_threaded (struct cgroup *cgrp) +bool cgroup_is_threaded (struct cgroup *cgrp) {return cgrp->dom_cgrp != cgrp; }
@@ -372,7 +372,7 @@ static bool cgroup_can_be_thread_root(struct cgroup *cgrp) }/* is @cgrp root of a threaded subtree? */ -static bool cgroup_is_thread_root (struct cgroup *cgrp) +bool cgroup_is_thread_root (struct cgroup *cgrp) {/* thread root should be a domain */ if (cgroup_is_threaded (cgrp))
kernel/cgroup/debug.c +44 -14
87 lines not on this page · raw message
Signature · 1 line
2.9.3
Waiman Long
maintainerRe: [PATCH 6/6] cgroup: update debug controller to print out thread mode information
Quoted 60 lines · Tejun Heo
From: Waiman Long <[email protected]>
Update debug controller so that it prints out debug info about thread mode.
1) The relationship between
proc_csetandthreaded_csetsare displayed.
2) The status of being a thread root or threaded cgroup is displayed.This patch is extracted from Waiman's larger patch.
Patch-originally-by Waiman Long <[email protected]>Signed-off-by Tejun Heo <[email protected]>--- kernel/cgroup/cgroup-internal.h | 2 ++ kernel/cgroup/cgroup.c | 4 +-- kernel/cgroup/debug.c | 58 +++++++++++++++++++++++++++++++---------- 3 files changed, 48 insertions(+), 16 deletions(-)kernel/cgroup/cgroup-internal.h +2
-0@@ -153,6 +153,8 @@ static inline void get_css_set(struct css_set *cset)bool cgroup_ssid_enabled (int ssid);bool cgroup_on_dfl (const struct cgroup *cgrp); +bool cgroup_is_thread_root (struct cgroup *cgrp); +bool cgroup_is_threaded (struct cgroup *cgrp);struct cgroup_root *cgroup_root_from_kf (struct kernfs_root *kf_root); struct cgroup *task_cgroup_from_root(struct task_struct *task,kernel/cgroup/cgroup.c +2
-2@@ -333,7 +333,7 @@ static bool cgroup_has_tasks(struct cgroup *cgrp)return cgrp->nr_populated_csets; } -static bool cgroup_is_threaded (struct cgroup *cgrp) +bool cgroup_is_threaded (struct cgroup *cgrp) {return cgrp->dom_cgrp != cgrp; }@@ -372,7 +372,7 @@ static bool cgroup_can_be_thread_root(struct cgroup *cgrp) }/* is @cgrp root of a threaded subtree? */ -static bool cgroup_is_thread_root (struct cgroup *cgrp) +bool cgroup_is_thread_root (struct cgroup *cgrp) {/* thread root should be a domain */ if (cgroup_is_threaded (cgrp))kernel/cgroup/debug.c +0
-0@@ -114,27 +114,54 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v) {struct cgroup_subsys_state *css =seq_css (seq);
kernel/cgroup/debug.c static int cgroup_css_links_read(struct seq_file *seq, void *v) · line 124
Quoted 10 lines
kernel/cgroup/debug.c +6
-1struct cgrp_cset_link *link; -int dead_cnt =0 , extra_refs =0 ; +int dead_cnt =0 , extra_refs =0 , threaded_csets =0 ;spin_lock_irq (&css_set_lock); + +if (cgroup_is_thread_root (css->cgroup)) +seq_puts (seq,"[thread root]\n" ); +else if (cgroup_is_threaded (css->cgroup)) +seq_puts (seq,"[threaded]\n" );
The cgroup status will not be needed anymore as you have introduced the cgroup.type control file that returns the proper information.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 6/6] cgroup: update debug controller to print out thread mode information
Hello,
Quoted 7 lines · Waiman Long
kernel/cgroup/debug.c static int cgroup_css_links_read(struct seq_file *seq, void *v) · line 124
Quoted 4 lines
kernel/cgroup/debug.c +4
-0+if (cgroup_is_thread_root (css->cgroup)) +seq_puts (seq,"[thread root]\n" ); +else if (cgroup_is_threaded (css->cgroup)) +seq_puts (seq,"[threaded]\n" );The cgroup status will not be needed anymore as you have introduced the cgroup.type control file that returns the proper information.
Ah, right, will drop this file.
Thanks.
Signature · 1 line
tejun
Waiman Long
maintainerRe: [PATCH 6/6] cgroup: update debug controller to print out thread mode information
Quoted 9 lines · Tejun Heo
Hello,
Quoted 6 lines · Waiman Long
kernel/cgroup/debug.c static int cgroup_css_links_read(struct seq_file *seq, void *v) · line 124
Quoted 4 lines
kernel/cgroup/debug.c +4
-0+if (cgroup_is_thread_root (css->cgroup)) +seq_puts (seq,"[thread root]\n" ); +else if (cgroup_is_threaded (css->cgroup)) +seq_puts (seq,"[threaded]\n" );The cgroup status will not be needed anymore as you have introduced the cgroup.type control file that returns the proper information.
Quoted 4 lines
Ah, right, will drop this file.
Thanks.
Oh, I am not saying that we should drop the whole patch. I just want to drop the above 4 line of codes as they are not needed.
Thanks,
Longman
Tejun Heo
maintainerRe: [PATCH 6/6] cgroup: update debug controller to print out thread mode information
Quoted 10 lines · Waiman Long
Quoted 9 lines · Tejun Heo
Hello,
Quoted 6 lines · Waiman Long
kernel/cgroup/debug.c static int cgroup_css_links_read(struct seq_file *seq, void *v) · line 124
Quoted 4 lines
kernel/cgroup/debug.c +4
-0+if (cgroup_is_thread_root (css->cgroup)) +seq_puts (seq,"[thread root]\n" ); +else if (cgroup_is_threaded (css->cgroup)) +seq_puts (seq,"[threaded]\n" );The cgroup status will not be needed anymore as you have introduced the cgroup.type control file that returns the proper information.
Quoted 6 lines
Quoted 4 lines
Ah, right, will drop this file.
Thanks.
Oh, I am not saying that we should drop the whole patch. I just want to drop the above 4 line of codes as they are not needed.
lol, yeah, that's me mis-writing. I'm gonna drop only the duplicate part.
Thanks.
Signature · 1 line
tejun
Waiman Long
maintainerQuoted 60 lines · Tejun Heo
Hello,
This is v3 of cgroup2 thread mode patchset. The changes from v2[L] are
* Switched to marking each cgroup threaded instead of doing it per-subtree as suggested by PeterZ. This allows more flexibility and removes certain interface quirks.
* Dropped RFC tag and excluded cpu controller patches from this patchset as threaded mode behaviors can easily be verified with the pid controller. Will follow up with cpu controller patchset later.
It is largely based on the discussions that we had at the plumbers last year. Here's the rough outline.
* Thread mode is explicitly enabled on a cgroup by writing "threaded" into "cgroup.type" file. The cgroup shouldn't have any processes or child cgroups. A threaded cgroup joins the the parent's resource domain and becomes a part of the threaded subtree anchored at the nearest domain ancestor, which is called the threaded domain cgroup of the subtree.
* Threads can be put anywhere in a threaded subtree by writing TIDs into "cgroup.threads" file. Process granularity and no-internal-process constraint don't apply in a threaded subtree.
* To be used in a threaded subtree, controllers should explicitly declare thread mode support and should be able to handle internal competition in some way.
* The threaded domain cgroup of a threaded subtree serves as the resource domain for the whole subtree. This is where all the controllers are guaranteed to have a common ground and resource consumptions in the threaded subtree which aren't tied to a specific thread are charged. Non-threaded controllers never see beyond thread root and can assume that all controllers will follow the same rules upto that point.
* Unlike other cgroups, the system root cgroup can serve as parent to domain child cgroups and threaded domains to threaded subtrees.
This allows threaded controllers to implement thread granular resource control without getting in the way of system level resource partitioning.
For more details on the interface and behavior, please refer to 0005.
This patchset contains the following six patches.
0001-cgroup-reorganize-cgroup.procs-task-write-path.patch 0002-cgroup-add-flags-to-css_task_iter_start-and-implemen.patch 0003-cgroup-introduce-cgroup-dom_cgrp-and-threaded-css_se.patch 0004-cgroup-implement-CSS_TASK_ITER_THREADED.patch 0005-cgroup-implement-cgroup-v2-thread-support.patch 0006-cgroup-update-debug-controller-to-print-out-thread-m.patch
0001-0005 implement cgroup2 thread mode. 0006 enables debug controller on it.
Quoted 6 lines
The patchset is based on the current cgroup/for-4.14
27f26753f8c0("cgroup: replacecss_setwalking populated test with testingcgrp->nr_populated_csets") and also available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.gitreview-cgroup2-threads-v3
Your new patches don't seem to be pushed to your git tree yet. I couldn't find them there.
Cheers,
Longman
Tejun Heo
maintainerQuoted 4 lines · Waiman Long
Quoted 1 line
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.gitreview-cgroup2-threads-v3Your new patches don't seem to be pushed to your git tree yet. I couldn't find them there.
Oops, pushed out now.
Thanks.
Signature · 1 line
tejun