|
@@ -36,10 +36,37 @@ static u64 debug_taskcount_read(struct cgroup_subsys_state *css,
|
|
return cgroup_task_count(css->cgroup);
|
|
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->nr_tasks)
|
|
|
|
+ seq_printf(seq, " +%d", refcnt - cset->nr_tasks);
|
|
|
|
+ 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,
|
|
static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
|
|
@@ -84,31 +111,126 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v)
|
|
{
|
|
{
|
|
struct cgroup_subsys_state *css = seq_css(seq);
|
|
struct cgroup_subsys_state *css = seq_css(seq);
|
|
struct cgrp_cset_link *link;
|
|
struct cgrp_cset_link *link;
|
|
|
|
+ int dead_cnt = 0, extra_refs = 0;
|
|
|
|
|
|
spin_lock_irq(&css_set_lock);
|
|
spin_lock_irq(&css_set_lock);
|
|
list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
|
|
list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
|
|
struct css_set *cset = link->cset;
|
|
struct css_set *cset = link->cset;
|
|
struct task_struct *task;
|
|
struct task_struct *task;
|
|
int count = 0;
|
|
int count = 0;
|
|
|
|
+ int refcnt = refcount_read(&cset->refcount);
|
|
|
|
|
|
- seq_printf(seq, "css_set %pK\n", cset);
|
|
|
|
|
|
+ seq_printf(seq, " %d", refcnt);
|
|
|
|
+ if (refcnt - cset->nr_tasks > 0) {
|
|
|
|
+ int extra = refcnt - cset->nr_tasks;
|
|
|
|
+
|
|
|
|
+ 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) {
|
|
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) {
|
|
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));
|
|
}
|
|
}
|
|
- continue;
|
|
|
|
- overflow:
|
|
|
|
- seq_puts(seq, " ...\n");
|
|
|
|
|
|
+ /* 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++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ WARN_ON(count != cset->nr_tasks);
|
|
}
|
|
}
|
|
spin_unlock_irq(&css_set_lock);
|
|
spin_unlock_irq(&css_set_lock);
|
|
|
|
+
|
|
|
|
+ if (!dead_cnt && !extra_refs)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ seq_puts(seq, "\n");
|
|
|
|
+ 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');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&cgroup_mutex);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -126,17 +248,20 @@ static struct cftype debug_files[] = {
|
|
|
|
|
|
{
|
|
{
|
|
.name = "current_css_set",
|
|
.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",
|
|
.name = "current_css_set_refcount",
|
|
.read_u64 = current_css_set_refcount_read,
|
|
.read_u64 = current_css_set_refcount_read,
|
|
|
|
+ .flags = CFTYPE_ONLY_ON_ROOT,
|
|
},
|
|
},
|
|
|
|
|
|
{
|
|
{
|
|
.name = "current_css_set_cg_links",
|
|
.name = "current_css_set_cg_links",
|
|
.seq_show = current_css_set_cg_links_read,
|
|
.seq_show = current_css_set_cg_links_read,
|
|
|
|
+ .flags = CFTYPE_ONLY_ON_ROOT,
|
|
},
|
|
},
|
|
|
|
|
|
{
|
|
{
|
|
@@ -144,6 +269,16 @@ static struct cftype debug_files[] = {
|
|
.seq_show = cgroup_css_links_read,
|
|
.seq_show = cgroup_css_links_read,
|
|
},
|
|
},
|
|
|
|
|
|
|
|
+ {
|
|
|
|
+ .name = "cgroup_subsys_states",
|
|
|
|
+ .seq_show = cgroup_subsys_states_read,
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ {
|
|
|
|
+ .name = "cgroup_masks",
|
|
|
|
+ .seq_show = cgroup_masks_read,
|
|
|
|
+ },
|
|
|
|
+
|
|
{
|
|
{
|
|
.name = "releasable",
|
|
.name = "releasable",
|
|
.read_u64 = releasable_read,
|
|
.read_u64 = releasable_read,
|
|
@@ -153,7 +288,8 @@ static struct cftype debug_files[] = {
|
|
};
|
|
};
|
|
|
|
|
|
struct cgroup_subsys debug_cgrp_subsys = {
|
|
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,
|
|
};
|
|
};
|