Skip to content

Commit

Permalink
cgroup: Make debug cgroup support v2 and thread mode
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Tejun Heo <[email protected]>
  • Loading branch information
Waiman-Long authored and htejun committed Jun 14, 2017
1 parent 23b0be4 commit 575313f
Showing 1 changed file with 153 additions and 17 deletions.
170 changes: 153 additions & 17 deletions kernel/cgroup/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand All @@ -126,24 +248,37 @@ 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,
},

{
.name = "cgroup_css_links",
.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,
Expand All @@ -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,
};

0 comments on commit 575313f

Please sign in to comment.