diff options
Diffstat (limited to 'kernel/cgroup/debug.c')
-rw-r--r-- | kernel/cgroup/debug.c | 170 |
1 files changed, 153 insertions, 17 deletions
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c index cbe77a2087c5..057d9b07f461 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, | |||
36 | return cgroup_task_count(css->cgroup); | 36 | return cgroup_task_count(css->cgroup); |
37 | } | 37 | } |
38 | 38 | ||
39 | static u64 current_css_set_read(struct cgroup_subsys_state *css, | 39 | static int current_css_set_read(struct seq_file *seq, void *v) |
40 | struct cftype *cft) | ||
41 | { | 40 | { |
42 | return (u64)(unsigned long)current->cgroups; | 41 | struct css_set *cset; |
42 | struct cgroup_subsys *ss; | ||
43 | struct cgroup_subsys_state *css; | ||
44 | int i, refcnt; | ||
45 | |||
46 | mutex_lock(&cgroup_mutex); | ||
47 | spin_lock_irq(&css_set_lock); | ||
48 | rcu_read_lock(); | ||
49 | cset = rcu_dereference(current->cgroups); | ||
50 | refcnt = refcount_read(&cset->refcount); | ||
51 | seq_printf(seq, "css_set %pK %d", cset, refcnt); | ||
52 | if (refcnt > cset->nr_tasks) | ||
53 | seq_printf(seq, " +%d", refcnt - cset->nr_tasks); | ||
54 | seq_puts(seq, "\n"); | ||
55 | |||
56 | /* | ||
57 | * Print the css'es stored in the current css_set. | ||
58 | */ | ||
59 | for_each_subsys(ss, i) { | ||
60 | css = cset->subsys[ss->id]; | ||
61 | if (!css) | ||
62 | continue; | ||
63 | seq_printf(seq, "%2d: %-4s\t- %lx[%d]\n", ss->id, ss->name, | ||
64 | (unsigned long)css, css->id); | ||
65 | } | ||
66 | rcu_read_unlock(); | ||
67 | spin_unlock_irq(&css_set_lock); | ||
68 | mutex_unlock(&cgroup_mutex); | ||
69 | return 0; | ||
43 | } | 70 | } |
44 | 71 | ||
45 | static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css, | 72 | 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) | |||
84 | { | 111 | { |
85 | struct cgroup_subsys_state *css = seq_css(seq); | 112 | struct cgroup_subsys_state *css = seq_css(seq); |
86 | struct cgrp_cset_link *link; | 113 | struct cgrp_cset_link *link; |
114 | int dead_cnt = 0, extra_refs = 0; | ||
87 | 115 | ||
88 | spin_lock_irq(&css_set_lock); | 116 | spin_lock_irq(&css_set_lock); |
89 | list_for_each_entry(link, &css->cgroup->cset_links, cset_link) { | 117 | list_for_each_entry(link, &css->cgroup->cset_links, cset_link) { |
90 | struct css_set *cset = link->cset; | 118 | struct css_set *cset = link->cset; |
91 | struct task_struct *task; | 119 | struct task_struct *task; |
92 | int count = 0; | 120 | int count = 0; |
121 | int refcnt = refcount_read(&cset->refcount); | ||
93 | 122 | ||
94 | seq_printf(seq, "css_set %pK\n", cset); | 123 | seq_printf(seq, " %d", refcnt); |
124 | if (refcnt - cset->nr_tasks > 0) { | ||
125 | int extra = refcnt - cset->nr_tasks; | ||
126 | |||
127 | seq_printf(seq, " +%d", extra); | ||
128 | /* | ||
129 | * Take out the one additional reference in | ||
130 | * init_css_set. | ||
131 | */ | ||
132 | if (cset == &init_css_set) | ||
133 | extra--; | ||
134 | extra_refs += extra; | ||
135 | } | ||
136 | seq_puts(seq, "\n"); | ||
95 | 137 | ||
96 | list_for_each_entry(task, &cset->tasks, cg_list) { | 138 | list_for_each_entry(task, &cset->tasks, cg_list) { |
97 | if (count++ > MAX_TASKS_SHOWN_PER_CSS) | 139 | if (count++ <= MAX_TASKS_SHOWN_PER_CSS) |
98 | goto overflow; | 140 | seq_printf(seq, " task %d\n", |
99 | seq_printf(seq, " task %d\n", task_pid_vnr(task)); | 141 | task_pid_vnr(task)); |
100 | } | 142 | } |
101 | 143 | ||
102 | list_for_each_entry(task, &cset->mg_tasks, cg_list) { | 144 | list_for_each_entry(task, &cset->mg_tasks, cg_list) { |
103 | if (count++ > MAX_TASKS_SHOWN_PER_CSS) | 145 | if (count++ <= MAX_TASKS_SHOWN_PER_CSS) |
104 | goto overflow; | 146 | seq_printf(seq, " task %d\n", |
105 | seq_printf(seq, " task %d\n", task_pid_vnr(task)); | 147 | task_pid_vnr(task)); |
106 | } | 148 | } |
107 | continue; | 149 | /* show # of overflowed tasks */ |
108 | overflow: | 150 | if (count > MAX_TASKS_SHOWN_PER_CSS) |
109 | seq_puts(seq, " ...\n"); | 151 | seq_printf(seq, " ... (%d)\n", |
152 | count - MAX_TASKS_SHOWN_PER_CSS); | ||
153 | |||
154 | if (cset->dead) { | ||
155 | seq_puts(seq, " [dead]\n"); | ||
156 | dead_cnt++; | ||
157 | } | ||
158 | |||
159 | WARN_ON(count != cset->nr_tasks); | ||
110 | } | 160 | } |
111 | spin_unlock_irq(&css_set_lock); | 161 | spin_unlock_irq(&css_set_lock); |
162 | |||
163 | if (!dead_cnt && !extra_refs) | ||
164 | return 0; | ||
165 | |||
166 | seq_puts(seq, "\n"); | ||
167 | if (extra_refs) | ||
168 | seq_printf(seq, "extra references = %d\n", extra_refs); | ||
169 | if (dead_cnt) | ||
170 | seq_printf(seq, "dead css_sets = %d\n", dead_cnt); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int cgroup_subsys_states_read(struct seq_file *seq, void *v) | ||
176 | { | ||
177 | struct cgroup *cgrp = seq_css(seq)->cgroup; | ||
178 | struct cgroup_subsys *ss; | ||
179 | struct cgroup_subsys_state *css; | ||
180 | char pbuf[16]; | ||
181 | int i; | ||
182 | |||
183 | mutex_lock(&cgroup_mutex); | ||
184 | for_each_subsys(ss, i) { | ||
185 | css = rcu_dereference_check(cgrp->subsys[ss->id], true); | ||
186 | if (!css) | ||
187 | continue; | ||
188 | |||
189 | pbuf[0] = '\0'; | ||
190 | |||
191 | /* Show the parent CSS if applicable*/ | ||
192 | if (css->parent) | ||
193 | snprintf(pbuf, sizeof(pbuf) - 1, " P=%d", | ||
194 | css->parent->id); | ||
195 | seq_printf(seq, "%2d: %-4s\t- %lx[%d] %d%s\n", ss->id, ss->name, | ||
196 | (unsigned long)css, css->id, | ||
197 | atomic_read(&css->online_cnt), pbuf); | ||
198 | } | ||
199 | mutex_unlock(&cgroup_mutex); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int cgroup_masks_read(struct seq_file *seq, void *v) | ||
204 | { | ||
205 | struct cgroup *cgrp = seq_css(seq)->cgroup; | ||
206 | struct cgroup_subsys *ss; | ||
207 | int i, j; | ||
208 | struct { | ||
209 | u16 *mask; | ||
210 | char *name; | ||
211 | } mask_list[] = { | ||
212 | { &cgrp->subtree_control, "subtree_control" }, | ||
213 | { &cgrp->subtree_ss_mask, "subtree_ss_mask" }, | ||
214 | }; | ||
215 | |||
216 | mutex_lock(&cgroup_mutex); | ||
217 | for (i = 0; i < ARRAY_SIZE(mask_list); i++) { | ||
218 | u16 mask = *mask_list[i].mask; | ||
219 | bool first = true; | ||
220 | |||
221 | seq_printf(seq, "%-17s: ", mask_list[i].name); | ||
222 | for_each_subsys(ss, j) { | ||
223 | if (!(mask & (1 << ss->id))) | ||
224 | continue; | ||
225 | if (!first) | ||
226 | seq_puts(seq, ", "); | ||
227 | seq_puts(seq, ss->name); | ||
228 | first = false; | ||
229 | } | ||
230 | seq_putc(seq, '\n'); | ||
231 | } | ||
232 | |||
233 | mutex_unlock(&cgroup_mutex); | ||
112 | return 0; | 234 | return 0; |
113 | } | 235 | } |
114 | 236 | ||
@@ -126,17 +248,20 @@ static struct cftype debug_files[] = { | |||
126 | 248 | ||
127 | { | 249 | { |
128 | .name = "current_css_set", | 250 | .name = "current_css_set", |
129 | .read_u64 = current_css_set_read, | 251 | .seq_show = current_css_set_read, |
252 | .flags = CFTYPE_ONLY_ON_ROOT, | ||
130 | }, | 253 | }, |
131 | 254 | ||
132 | { | 255 | { |
133 | .name = "current_css_set_refcount", | 256 | .name = "current_css_set_refcount", |
134 | .read_u64 = current_css_set_refcount_read, | 257 | .read_u64 = current_css_set_refcount_read, |
258 | .flags = CFTYPE_ONLY_ON_ROOT, | ||
135 | }, | 259 | }, |
136 | 260 | ||
137 | { | 261 | { |
138 | .name = "current_css_set_cg_links", | 262 | .name = "current_css_set_cg_links", |
139 | .seq_show = current_css_set_cg_links_read, | 263 | .seq_show = current_css_set_cg_links_read, |
264 | .flags = CFTYPE_ONLY_ON_ROOT, | ||
140 | }, | 265 | }, |
141 | 266 | ||
142 | { | 267 | { |
@@ -145,6 +270,16 @@ static struct cftype debug_files[] = { | |||
145 | }, | 270 | }, |
146 | 271 | ||
147 | { | 272 | { |
273 | .name = "cgroup_subsys_states", | ||
274 | .seq_show = cgroup_subsys_states_read, | ||
275 | }, | ||
276 | |||
277 | { | ||
278 | .name = "cgroup_masks", | ||
279 | .seq_show = cgroup_masks_read, | ||
280 | }, | ||
281 | |||
282 | { | ||
148 | .name = "releasable", | 283 | .name = "releasable", |
149 | .read_u64 = releasable_read, | 284 | .read_u64 = releasable_read, |
150 | }, | 285 | }, |
@@ -153,7 +288,8 @@ static struct cftype debug_files[] = { | |||
153 | }; | 288 | }; |
154 | 289 | ||
155 | struct cgroup_subsys debug_cgrp_subsys = { | 290 | struct cgroup_subsys debug_cgrp_subsys = { |
156 | .css_alloc = debug_css_alloc, | 291 | .css_alloc = debug_css_alloc, |
157 | .css_free = debug_css_free, | 292 | .css_free = debug_css_free, |
158 | .legacy_cftypes = debug_files, | 293 | .legacy_cftypes = debug_files, |
294 | .dfl_cftypes = debug_files, | ||
159 | }; | 295 | }; |