* [PATCH-cgroup 1/5] cgroup: Keep accurate count of tasks in each css_set
2017-06-13 21:18 [PATCH-cgroup 0/5] cgroup: Make debug controller useful for debugging Waiman Long
@ 2017-06-13 21:18 ` Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 2/5] cgroup: Move debug cgroup to its own file Waiman Long
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Waiman Long @ 2017-06-13 21:18 UTC (permalink / raw)
To: Tejun Heo, Li Zefan, Johannes Weiner, Peter Zijlstra, Ingo Molnar
Cc: cgroups, linux-kernel, kernel-team, pjt, luto, efault, torvalds,
Waiman Long
The reference count in the css_set data structure was used as a
proxy of the number of tasks attached to that css_set. However, that
count is actually not an accurate measure especially with thread mode
support. So a new variable task_count is added to the css_set to keep
track of the actual task count. This new variable is protected by
the css_set_lock. Functions that require the actual task count are
updated to use the new variable.
Signed-off-by: Waiman Long <longman@redhat.com>
---
include/linux/cgroup-defs.h | 3 +++
kernel/cgroup/cgroup-v1.c | 6 +-----
kernel/cgroup/cgroup.c | 12 +++++++++++-
3 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index fb694b9..ea3218a 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -163,6 +163,9 @@ struct css_set {
/* reference count */
refcount_t refcount;
+ /* internal task count, protected by css_set_lock */
+ int task_count;
+
/*
* If not threaded, the following points to self. If threaded, to
* a cset which belongs to the top cgroup of the threaded subtree.
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 1e101b9..9bbd4ef 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -334,10 +334,6 @@ static struct cgroup_pidlist *cgroup_pidlist_find_create(struct cgroup *cgrp,
/**
* cgroup_task_count - count the number of tasks in a cgroup.
* @cgrp: the cgroup in question
- *
- * Return the number of tasks in the cgroup. The returned number can be
- * higher than the actual number of tasks due to css_set references from
- * namespace roots and temporary usages.
*/
static int cgroup_task_count(const struct cgroup *cgrp)
{
@@ -346,7 +342,7 @@ static int cgroup_task_count(const struct cgroup *cgrp)
spin_lock_irq(&css_set_lock);
list_for_each_entry(link, &cgrp->cset_links, cset_link)
- count += refcount_read(&link->cset->refcount);
+ count += link->cset->task_count;
spin_unlock_irq(&css_set_lock);
return count;
}
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index d319438..216657e 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -647,6 +647,11 @@ static bool css_set_threaded(struct css_set *cset)
/**
* css_set_populated - does a css_set contain any tasks?
* @cset: target css_set
+ *
+ * css_set_populated() should be the same as !!cset->task_count at steady
+ * state. However, css_set_populated() can be called while a task is being
+ * added to or removed from the linked list before the task_count is
+ * properly updated. Hence, we can't just look at ->task_count here.
*/
static bool css_set_populated(struct css_set *cset)
{
@@ -668,7 +673,7 @@ static bool cgroup_has_tasks(struct cgroup *cgrp)
spin_lock_irq(&css_set_lock);
list_for_each_entry(link, &cgrp->cset_links, cset_link) {
- if (css_set_populated(link->cset)) {
+ if (link->cset->task_count) {
has_tasks = true;
break;
}
@@ -1758,6 +1763,7 @@ static void cgroup_enable_task_cg_lists(void)
css_set_update_populated(cset, true);
list_add_tail(&p->cg_list, &cset->tasks);
get_css_set(cset);
+ cset->task_count++;
}
spin_unlock(&p->sighand->siglock);
} while_each_thread(g, p);
@@ -2241,8 +2247,10 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
struct css_set *to_cset = cset->mg_dst_cset;
get_css_set(to_cset);
+ to_cset->task_count++;
css_set_move_task(task, from_cset, to_cset, true);
put_css_set_locked(from_cset);
+ from_cset->task_count--;
}
}
spin_unlock_irq(&css_set_lock);
@@ -5236,6 +5244,7 @@ void cgroup_post_fork(struct task_struct *child)
cset = task_css_set(current);
if (list_empty(&child->cg_list)) {
get_css_set(cset);
+ cset->task_count++;
css_set_move_task(child, NULL, cset, false);
}
spin_unlock_irq(&css_set_lock);
@@ -5285,6 +5294,7 @@ void cgroup_exit(struct task_struct *tsk)
if (!list_empty(&tsk->cg_list)) {
spin_lock_irq(&css_set_lock);
css_set_move_task(tsk, cset, NULL, false);
+ cset->task_count--;
spin_unlock_irq(&css_set_lock);
} else {
get_css_set(cset);
--
1.8.3.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH-cgroup 2/5] cgroup: Move debug cgroup to its own file
2017-06-13 21:18 [PATCH-cgroup 0/5] cgroup: Make debug controller useful for debugging Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 1/5] cgroup: Keep accurate count of tasks in each css_set Waiman Long
@ 2017-06-13 21:18 ` Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 3/5] cgroup: Make Kconfig prompt of debug cgroup more accurate Waiman Long
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Waiman Long @ 2017-06-13 21:18 UTC (permalink / raw)
To: Tejun Heo, Li Zefan, Johannes Weiner, Peter Zijlstra, Ingo Molnar
Cc: cgroups, linux-kernel, kernel-team, pjt, luto, efault, torvalds,
Waiman Long
The debug cgroup currently resides within cgroup-v1.c and is enabled
only for v1 cgroup. To enable the debug cgroup also for v2, it makes
sense to put the code into its own file as it will no longer be v1
specific. There is no change to the debug cgroup specific code.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/Makefile | 1 +
kernel/cgroup/cgroup-internal.h | 2 +
kernel/cgroup/cgroup-v1.c | 149 +-------------------------------------
kernel/cgroup/debug.c | 153 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 157 insertions(+), 148 deletions(-)
create mode 100644 kernel/cgroup/debug.c
diff --git a/kernel/cgroup/Makefile b/kernel/cgroup/Makefile
index 387348a..ce693cc 100644
--- a/kernel/cgroup/Makefile
+++ b/kernel/cgroup/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_CGROUP_FREEZER) += freezer.o
obj-$(CONFIG_CGROUP_PIDS) += pids.o
obj-$(CONFIG_CGROUP_RDMA) += rdma.o
obj-$(CONFIG_CPUSETS) += cpuset.o
+obj-$(CONFIG_CGROUP_DEBUG) += debug.o
diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h
index 2c8e3a9..0e81c61 100644
--- a/kernel/cgroup/cgroup-internal.h
+++ b/kernel/cgroup/cgroup-internal.h
@@ -192,6 +192,8 @@ void cgroup_procs_write_finish(struct task_struct *task)
int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
struct kernfs_root *kf_root);
+int cgroup_task_count(const struct cgroup *cgrp);
+
/*
* namespace.c
*/
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 9bbd4ef..fcbdb09 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -335,7 +335,7 @@ static struct cgroup_pidlist *cgroup_pidlist_find_create(struct cgroup *cgrp,
* cgroup_task_count - count the number of tasks in a cgroup.
* @cgrp: the cgroup in question
*/
-static int cgroup_task_count(const struct cgroup *cgrp)
+int cgroup_task_count(const struct cgroup *cgrp)
{
int count = 0;
struct cgrp_cset_link *link;
@@ -1307,150 +1307,3 @@ static int __init cgroup_no_v1(char *str)
return 1;
}
__setup("cgroup_no_v1=", cgroup_no_v1);
-
-
-#ifdef CONFIG_CGROUP_DEBUG
-static struct cgroup_subsys_state *
-debug_css_alloc(struct cgroup_subsys_state *parent_css)
-{
- struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
-
- if (!css)
- return ERR_PTR(-ENOMEM);
-
- return css;
-}
-
-static void debug_css_free(struct cgroup_subsys_state *css)
-{
- kfree(css);
-}
-
-static u64 debug_taskcount_read(struct cgroup_subsys_state *css,
- struct cftype *cft)
-{
- return cgroup_task_count(css->cgroup);
-}
-
-static u64 current_css_set_read(struct cgroup_subsys_state *css,
- struct cftype *cft)
-{
- return (u64)(unsigned long)current->cgroups;
-}
-
-static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
- struct cftype *cft)
-{
- u64 count;
-
- rcu_read_lock();
- count = refcount_read(&task_css_set(current)->refcount);
- rcu_read_unlock();
- return count;
-}
-
-static int current_css_set_cg_links_read(struct seq_file *seq, void *v)
-{
- struct cgrp_cset_link *link;
- struct css_set *cset;
- char *name_buf;
-
- name_buf = kmalloc(NAME_MAX + 1, GFP_KERNEL);
- if (!name_buf)
- return -ENOMEM;
-
- spin_lock_irq(&css_set_lock);
- rcu_read_lock();
- cset = rcu_dereference(current->cgroups);
- list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
- struct cgroup *c = link->cgrp;
-
- cgroup_name(c, name_buf, NAME_MAX + 1);
- seq_printf(seq, "Root %d group %s\n",
- c->root->hierarchy_id, name_buf);
- }
- rcu_read_unlock();
- spin_unlock_irq(&css_set_lock);
- kfree(name_buf);
- return 0;
-}
-
-#define MAX_TASKS_SHOWN_PER_CSS 25
-static int cgroup_css_links_read(struct seq_file *seq, void *v)
-{
- struct cgroup_subsys_state *css = seq_css(seq);
- struct cgrp_cset_link *link;
-
- spin_lock_irq(&css_set_lock);
- list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
- struct css_set *cset = link->cset;
- struct task_struct *task;
- int count = 0;
-
- seq_printf(seq, "css_set %pK\n", cset);
-
- list_for_each_entry(task, &cset->tasks, cg_list) {
- if (count++ > MAX_TASKS_SHOWN_PER_CSS)
- goto overflow;
- seq_printf(seq, " task %d\n", task_pid_vnr(task));
- }
-
- list_for_each_entry(task, &cset->mg_tasks, cg_list) {
- if (count++ > MAX_TASKS_SHOWN_PER_CSS)
- goto overflow;
- seq_printf(seq, " task %d\n", task_pid_vnr(task));
- }
- continue;
- overflow:
- seq_puts(seq, " ...\n");
- }
- spin_unlock_irq(&css_set_lock);
- return 0;
-}
-
-static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
-{
- return (!cgroup_is_populated(css->cgroup) &&
- !css_has_online_children(&css->cgroup->self));
-}
-
-static struct cftype debug_files[] = {
- {
- .name = "taskcount",
- .read_u64 = debug_taskcount_read,
- },
-
- {
- .name = "current_css_set",
- .read_u64 = current_css_set_read,
- },
-
- {
- .name = "current_css_set_refcount",
- .read_u64 = current_css_set_refcount_read,
- },
-
- {
- .name = "current_css_set_cg_links",
- .seq_show = current_css_set_cg_links_read,
- },
-
- {
- .name = "cgroup_css_links",
- .seq_show = cgroup_css_links_read,
- },
-
- {
- .name = "releasable",
- .read_u64 = releasable_read,
- },
-
- { } /* terminate */
-};
-
-struct cgroup_subsys debug_cgrp_subsys = {
- .css_alloc = debug_css_alloc,
- .css_free = debug_css_free,
- .legacy_cftypes = debug_files,
-};
-#endif /* CONFIG_CGROUP_DEBUG */
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c
new file mode 100644
index 0000000..1c209aa
--- /dev/null
+++ b/kernel/cgroup/debug.c
@@ -0,0 +1,153 @@
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include "cgroup-internal.h"
+
+static struct cgroup_subsys_state *
+debug_css_alloc(struct cgroup_subsys_state *parent_css)
+{
+ struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
+
+ if (!css)
+ return ERR_PTR(-ENOMEM);
+
+ return css;
+}
+
+static void debug_css_free(struct cgroup_subsys_state *css)
+{
+ kfree(css);
+}
+
+/*
+ * debug_taskcount_read - return the number of tasks in a cgroup.
+ * @cgrp: the cgroup in question
+ */
+static u64 debug_taskcount_read(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return cgroup_task_count(css->cgroup);
+}
+
+static u64 current_css_set_read(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ return (u64)(unsigned long)current->cgroups;
+}
+
+static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ u64 count;
+
+ rcu_read_lock();
+ count = refcount_read(&task_css_set(current)->refcount);
+ rcu_read_unlock();
+ return count;
+}
+
+static int current_css_set_cg_links_read(struct seq_file *seq, void *v)
+{
+ struct cgrp_cset_link *link;
+ struct css_set *cset;
+ char *name_buf;
+
+ name_buf = kmalloc(NAME_MAX + 1, GFP_KERNEL);
+ if (!name_buf)
+ return -ENOMEM;
+
+ spin_lock_irq(&css_set_lock);
+ rcu_read_lock();
+ cset = rcu_dereference(current->cgroups);
+ list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
+ struct cgroup *c = link->cgrp;
+
+ cgroup_name(c, name_buf, NAME_MAX + 1);
+ seq_printf(seq, "Root %d group %s\n",
+ c->root->hierarchy_id, name_buf);
+ }
+ rcu_read_unlock();
+ spin_unlock_irq(&css_set_lock);
+ kfree(name_buf);
+ return 0;
+}
+
+#define MAX_TASKS_SHOWN_PER_CSS 25
+static int cgroup_css_links_read(struct seq_file *seq, void *v)
+{
+ struct cgroup_subsys_state *css = seq_css(seq);
+ struct cgrp_cset_link *link;
+
+ spin_lock_irq(&css_set_lock);
+ list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
+ struct css_set *cset = link->cset;
+ struct task_struct *task;
+ int count = 0;
+
+ seq_printf(seq, "css_set %pK\n", cset);
+
+ list_for_each_entry(task, &cset->tasks, cg_list) {
+ if (count++ > MAX_TASKS_SHOWN_PER_CSS)
+ goto overflow;
+ seq_printf(seq, " task %d\n", task_pid_vnr(task));
+ }
+
+ list_for_each_entry(task, &cset->mg_tasks, cg_list) {
+ if (count++ > MAX_TASKS_SHOWN_PER_CSS)
+ goto overflow;
+ seq_printf(seq, " task %d\n", task_pid_vnr(task));
+ }
+ continue;
+ overflow:
+ seq_puts(seq, " ...\n");
+ }
+ spin_unlock_irq(&css_set_lock);
+ return 0;
+}
+
+static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
+{
+ return (!cgroup_is_populated(css->cgroup) &&
+ !css_has_online_children(&css->cgroup->self));
+}
+
+static struct cftype debug_files[] = {
+ {
+ .name = "taskcount",
+ .read_u64 = debug_taskcount_read,
+ },
+
+ {
+ .name = "current_css_set",
+ .read_u64 = current_css_set_read,
+ },
+
+ {
+ .name = "current_css_set_refcount",
+ .read_u64 = current_css_set_refcount_read,
+ },
+
+ {
+ .name = "current_css_set_cg_links",
+ .seq_show = current_css_set_cg_links_read,
+ },
+
+ {
+ .name = "cgroup_css_links",
+ .seq_show = cgroup_css_links_read,
+ },
+
+ {
+ .name = "releasable",
+ .read_u64 = releasable_read,
+ },
+
+ { } /* terminate */
+};
+
+struct cgroup_subsys debug_cgrp_subsys = {
+ .css_alloc = debug_css_alloc,
+ .css_free = debug_css_free,
+ .legacy_cftypes = debug_files,
+};
--
1.8.3.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH-cgroup 3/5] cgroup: Make Kconfig prompt of debug cgroup more accurate
2017-06-13 21:18 [PATCH-cgroup 0/5] cgroup: Make debug controller useful for debugging Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 1/5] cgroup: Keep accurate count of tasks in each css_set Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 2/5] cgroup: Move debug cgroup to its own file Waiman Long
@ 2017-06-13 21:18 ` Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 4/5] cgroup: Make debug cgroup support v2 and thread mode Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 5/5] cgroup: Enable debug controller only with cgroup_debug boot option Waiman Long
4 siblings, 0 replies; 6+ messages in thread
From: Waiman Long @ 2017-06-13 21:18 UTC (permalink / raw)
To: Tejun Heo, Li Zefan, Johannes Weiner, Peter Zijlstra, Ingo Molnar
Cc: cgroups, linux-kernel, kernel-team, pjt, luto, efault, torvalds,
Waiman Long
The Kconfig prompt and description of the debug cgroup controller
more accurate by saying that it is for debug purpose only and its
interfaces are unstable.
Signed-off-by: Waiman Long <longman@redhat.com>
---
init/Kconfig | 7 +++++--
kernel/cgroup/debug.c | 6 ++++++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/init/Kconfig b/init/Kconfig
index 1d3475f..5f9d139 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1205,11 +1205,14 @@ config CGROUP_BPF
inet sockets.
config CGROUP_DEBUG
- bool "Example controller"
+ bool "Debug controller"
default n
+ depends on DEBUG_KERNEL
help
This option enables a simple controller that exports
- debugging information about the cgroups framework.
+ debugging information about the cgroups framework. This
+ controller is for control cgroup debugging only. Its
+ interfaces are not stable.
Say N.
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c
index 1c209aa..cbe77a2 100644
--- a/kernel/cgroup/debug.c
+++ b/kernel/cgroup/debug.c
@@ -1,3 +1,9 @@
+/*
+ * Debug controller
+ *
+ * WARNING: This controller is for cgroup core debugging only.
+ * Its interfaces are unstable and subject to changes at any time.
+ */
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/slab.h>
--
1.8.3.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH-cgroup 4/5] cgroup: Make debug cgroup support v2 and thread mode
2017-06-13 21:18 [PATCH-cgroup 0/5] cgroup: Make debug controller useful for debugging Waiman Long
` (2 preceding siblings ...)
2017-06-13 21:18 ` [PATCH-cgroup 3/5] cgroup: Make Kconfig prompt of debug cgroup more accurate Waiman Long
@ 2017-06-13 21:18 ` Waiman Long
2017-06-13 21:18 ` [PATCH-cgroup 5/5] cgroup: Enable debug controller only with cgroup_debug boot option Waiman Long
4 siblings, 0 replies; 6+ messages in thread
From: Waiman Long @ 2017-06-13 21:18 UTC (permalink / raw)
To: Tejun Heo, Li Zefan, Johannes Weiner, Peter Zijlstra, Ingo Molnar
Cc: cgroups, linux-kernel, kernel-team, pjt, luto, efault, torvalds,
Waiman Long
Besides supporting cgroup v2 and thread mode, the following changes
are also made:
1) current_* cgroup files now resides only at the root as we don't
need duplicated files of the same function all over the cgroup
hierarchy.
2) The cgroup_css_links_read() function is modified to report
the number of tasks that are skipped because of overflow.
3) The relationship between proc_cset and threaded_csets are displayed.
4) The number of extra unaccounted references are displayed.
5) The status of being a thread root or threaded cgroup is displayed.
6) The current_css_set_read() function now prints out the addresses of
the css'es associated with the current css_set.
7) A new cgroup_subsys_states file is added to display the css objects
associated with a cgroup.
8) A new cgroup_masks file is added to display the various controller
bit masks in the cgroup.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/debug.c | 197 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 180 insertions(+), 17 deletions(-)
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c
index cbe77a2..82e5cbd 100644
--- a/kernel/cgroup/debug.c
+++ b/kernel/cgroup/debug.c
@@ -36,10 +36,37 @@ static u64 debug_taskcount_read(struct cgroup_subsys_state *css,
return cgroup_task_count(css->cgroup);
}
-static u64 current_css_set_read(struct cgroup_subsys_state *css,
- struct cftype *cft)
+static int current_css_set_read(struct seq_file *seq, void *v)
{
- return (u64)(unsigned long)current->cgroups;
+ struct css_set *cset;
+ struct cgroup_subsys *ss;
+ struct cgroup_subsys_state *css;
+ int i, refcnt;
+
+ mutex_lock(&cgroup_mutex);
+ spin_lock_irq(&css_set_lock);
+ rcu_read_lock();
+ cset = rcu_dereference(current->cgroups);
+ refcnt = refcount_read(&cset->refcount);
+ seq_printf(seq, "css_set %pK %d", cset, refcnt);
+ if (refcnt > cset->task_count)
+ seq_printf(seq, " +%d", refcnt - cset->task_count);
+ seq_puts(seq, "\n");
+
+ /*
+ * Print the css'es stored in the current css_set.
+ */
+ for_each_subsys(ss, i) {
+ css = cset->subsys[ss->id];
+ if (!css)
+ continue;
+ seq_printf(seq, "%2d: %-4s\t- %lx[%d]\n", ss->id, ss->name,
+ (unsigned long)css, css->id);
+ }
+ rcu_read_unlock();
+ spin_unlock_irq(&css_set_lock);
+ mutex_unlock(&cgroup_mutex);
+ return 0;
}
static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
@@ -84,31 +111,152 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v)
{
struct cgroup_subsys_state *css = seq_css(seq);
struct cgrp_cset_link *link;
+ int dead_cnt = 0, extra_refs = 0, threaded_csets = 0;
spin_lock_irq(&css_set_lock);
list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
struct css_set *cset = link->cset;
struct task_struct *task;
int count = 0;
+ int refcnt = refcount_read(&cset->refcount);
- seq_printf(seq, "css_set %pK\n", cset);
+ /*
+ * Print out the proc_cset and threaded_cset relationship
+ * and highlight difference between refcount and task_count.
+ */
+ seq_printf(seq, "css_set %pK", cset);
+ if (rcu_dereference_protected(cset->proc_cset, 1) != cset) {
+ threaded_csets++;
+ seq_printf(seq, "=>%pK", cset->proc_cset);
+ }
+ if (!list_empty(&cset->threaded_csets)) {
+ struct css_set *tcset;
+ int idx = 0;
+
+ list_for_each_entry(tcset, &cset->threaded_csets,
+ threaded_csets_node) {
+ seq_puts(seq, idx ? "," : "<=");
+ seq_printf(seq, "%pK", tcset);
+ idx++;
+ }
+ } else {
+ seq_printf(seq, " %d", refcnt);
+ if (refcnt - cset->task_count > 0) {
+ int extra = refcnt - cset->task_count;
+
+ seq_printf(seq, " +%d", extra);
+ /*
+ * Take out the one additional reference in
+ * init_css_set.
+ */
+ if (cset == &init_css_set)
+ extra--;
+ extra_refs += extra;
+ }
+ }
+ seq_puts(seq, "\n");
list_for_each_entry(task, &cset->tasks, cg_list) {
- if (count++ > MAX_TASKS_SHOWN_PER_CSS)
- goto overflow;
- seq_printf(seq, " task %d\n", task_pid_vnr(task));
+ if (count++ <= MAX_TASKS_SHOWN_PER_CSS)
+ seq_printf(seq, " task %d\n",
+ task_pid_vnr(task));
}
list_for_each_entry(task, &cset->mg_tasks, cg_list) {
- if (count++ > MAX_TASKS_SHOWN_PER_CSS)
- goto overflow;
- seq_printf(seq, " task %d\n", task_pid_vnr(task));
+ if (count++ <= MAX_TASKS_SHOWN_PER_CSS)
+ seq_printf(seq, " task %d\n",
+ task_pid_vnr(task));
+ }
+ /* show # of overflowed tasks */
+ if (count > MAX_TASKS_SHOWN_PER_CSS)
+ seq_printf(seq, " ... (%d)\n",
+ count - MAX_TASKS_SHOWN_PER_CSS);
+
+ if (cset->dead) {
+ seq_puts(seq, " [dead]\n");
+ dead_cnt++;
}
- continue;
- overflow:
- seq_puts(seq, " ...\n");
+
+ WARN_ON(count != cset->task_count);
}
spin_unlock_irq(&css_set_lock);
+
+ if (!dead_cnt && !extra_refs && !threaded_csets)
+ return 0;
+
+ seq_puts(seq, "\n");
+ if (threaded_csets)
+ seq_printf(seq, "threaded css_sets = %d\n", threaded_csets);
+ if (extra_refs)
+ seq_printf(seq, "extra references = %d\n", extra_refs);
+ if (dead_cnt)
+ seq_printf(seq, "dead css_sets = %d\n", dead_cnt);
+
+ return 0;
+}
+
+static int cgroup_subsys_states_read(struct seq_file *seq, void *v)
+{
+ struct cgroup *cgrp = seq_css(seq)->cgroup;
+ struct cgroup_subsys *ss;
+ struct cgroup_subsys_state *css;
+ char pbuf[16];
+ int i;
+
+ mutex_lock(&cgroup_mutex);
+ for_each_subsys(ss, i) {
+ css = rcu_dereference_check(cgrp->subsys[ss->id], true);
+ if (!css)
+ continue;
+
+ pbuf[0] = '\0';
+
+ /* Show the parent CSS if applicable*/
+ if (css->parent)
+ snprintf(pbuf, sizeof(pbuf) - 1, " P=%d",
+ css->parent->id);
+ seq_printf(seq, "%2d: %-4s\t- %lx[%d] %d%s\n", ss->id, ss->name,
+ (unsigned long)css, css->id,
+ atomic_read(&css->online_cnt), pbuf);
+ }
+ mutex_unlock(&cgroup_mutex);
+ return 0;
+}
+
+static int cgroup_masks_read(struct seq_file *seq, void *v)
+{
+ struct cgroup *cgrp = seq_css(seq)->cgroup;
+ struct cgroup_subsys *ss;
+ int i, j;
+ struct {
+ u16 *mask;
+ char *name;
+ } mask_list[] = {
+ { &cgrp->subtree_control, "subtree_control" },
+ { &cgrp->subtree_ss_mask, "subtree_ss_mask" },
+ };
+
+ mutex_lock(&cgroup_mutex);
+ for (i = 0; i < ARRAY_SIZE(mask_list); i++) {
+ u16 mask = *mask_list[i].mask;
+ bool first = true;
+
+ seq_printf(seq, "%-17s: ", mask_list[i].name);
+ for_each_subsys(ss, j) {
+ if (!(mask & (1 << ss->id)))
+ continue;
+ if (!first)
+ seq_puts(seq, ", ");
+ seq_puts(seq, ss->name);
+ first = false;
+ }
+ seq_putc(seq, '\n');
+ }
+ if (cgrp->proc_cgrp)
+ seq_printf(seq, "thread mode : %s\n",
+ (cgrp->proc_cgrp == cgrp) ? "root" : "threaded");
+
+ mutex_unlock(&cgroup_mutex);
return 0;
}
@@ -126,17 +274,20 @@ static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
{
.name = "current_css_set",
- .read_u64 = current_css_set_read,
+ .seq_show = current_css_set_read,
+ .flags = CFTYPE_ONLY_ON_ROOT,
},
{
.name = "current_css_set_refcount",
.read_u64 = current_css_set_refcount_read,
+ .flags = CFTYPE_ONLY_ON_ROOT,
},
{
.name = "current_css_set_cg_links",
.seq_show = current_css_set_cg_links_read,
+ .flags = CFTYPE_ONLY_ON_ROOT,
},
{
@@ -145,6 +296,16 @@ static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
},
{
+ .name = "cgroup_subsys_states",
+ .seq_show = cgroup_subsys_states_read,
+ },
+
+ {
+ .name = "cgroup_masks",
+ .seq_show = cgroup_masks_read,
+ },
+
+ {
.name = "releasable",
.read_u64 = releasable_read,
},
@@ -153,7 +314,9 @@ static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
};
struct cgroup_subsys debug_cgrp_subsys = {
- .css_alloc = debug_css_alloc,
- .css_free = debug_css_free,
- .legacy_cftypes = debug_files,
+ .css_alloc = debug_css_alloc,
+ .css_free = debug_css_free,
+ .legacy_cftypes = debug_files,
+ .dfl_cftypes = debug_files,
+ .threaded = true,
};
--
1.8.3.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH-cgroup 5/5] cgroup: Enable debug controller only with cgroup_debug boot option
2017-06-13 21:18 [PATCH-cgroup 0/5] cgroup: Make debug controller useful for debugging Waiman Long
` (3 preceding siblings ...)
2017-06-13 21:18 ` [PATCH-cgroup 4/5] cgroup: Make debug cgroup support v2 and thread mode Waiman Long
@ 2017-06-13 21:18 ` Waiman Long
4 siblings, 0 replies; 6+ messages in thread
From: Waiman Long @ 2017-06-13 21:18 UTC (permalink / raw)
To: Tejun Heo, Li Zefan, Johannes Weiner, Peter Zijlstra, Ingo Molnar
Cc: cgroups, linux-kernel, kernel-team, pjt, luto, efault, torvalds,
Waiman Long
As suggested by Tejun, the debug controller will be activated only when
the "cgroup_debug" option is specified in the kernel boot command line.
Hopefully, that will discourage people from using the debug controller
for any purpose other than cgroup core debugging.
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/debug.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c
index 82e5cbd..be901c0 100644
--- a/kernel/cgroup/debug.c
+++ b/kernel/cgroup/debug.c
@@ -320,3 +320,23 @@ struct cgroup_subsys debug_cgrp_subsys = {
.dfl_cftypes = debug_files,
.threaded = true,
};
+
+/*
+ * Disable the debug controller by hiding the debug cgroup control files
+ * if the kernel boot parameter "cgroup_debug" isn't set.
+ */
+static bool cgroup_debug_enable __initdata;
+static int __init enable_cgroup_debug(char *str)
+{
+ cgroup_debug_enable = true;
+ return 1;
+}
+__setup("cgroup_debug", enable_cgroup_debug);
+
+static int __init debug_init(void)
+{
+ if (!cgroup_debug_enable)
+ debug_files[0].name[0] = '\0';
+ return 0;
+}
+core_initcall(debug_init);
--
1.8.3.1
^ permalink raw reply [flat|nested] 6+ messages in thread