cgroup: Make debug cgroup support v2 and thread mode
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 number of extra unaccounted references are displayed. 4) The current_css_set_read() function now prints out the addresses of the css'es associated with the current css_set. 5) A new cgroup_subsys_states file is added to display the css objects associated with a cgroup. 6) A new cgroup_masks file is added to display the various controller bit masks in the cgroup. tj: Dropped thread mode related information for now so that debug controller changes aren't blocked on the thread mode. Signed-off-by: Waiman Long <longman@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
23b0be480f
commit
575313f40f
|
@ -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->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,
|
||||
|
@ -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 cgrp_cset_link *link;
|
||||
int dead_cnt = 0, extra_refs = 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);
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -126,17 +248,20 @@ static struct cftype debug_files[] = {
|
|||
|
||||
{
|
||||
.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,
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -144,6 +269,16 @@ static struct cftype debug_files[] = {
|
|||
.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",
|
||||
.read_u64 = releasable_read,
|
||||
|
@ -153,7 +288,8 @@ static struct cftype debug_files[] = {
|
|||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue