Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 575313f4 authored by Waiman Long's avatar Waiman Long Committed by Tejun Heo
Browse files

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: default avatarWaiman Long <longman@redhat.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent 23b0be48
Loading
Loading
Loading
Loading
+153 −17
Original line number Diff line number Diff line
@@ -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,
@@ -156,4 +291,5 @@ struct cgroup_subsys debug_cgrp_subsys = {
	.css_alloc	= debug_css_alloc,
	.css_free	= debug_css_free,
	.legacy_cftypes	= debug_files,
	.dfl_cftypes	= debug_files,
};