1 /* 2 * Debug controller 3 * 4 * WARNING: This controller is for cgroup core debugging only. 5 * Its interfaces are unstable and subject to changes at any time. 6 */ 7 #include <linux/ctype.h> 8 #include <linux/mm.h> 9 #include <linux/slab.h> 10 11 #include "cgroup-internal.h" 12 13 static struct cgroup_subsys_state * 14 debug_css_alloc(struct cgroup_subsys_state *parent_css) 15 { 16 struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL); 17 18 if (!css) 19 return ERR_PTR(-ENOMEM); 20 21 return css; 22 } 23 24 static void debug_css_free(struct cgroup_subsys_state *css) 25 { 26 kfree(css); 27 } 28 29 /* 30 * debug_taskcount_read - return the number of tasks in a cgroup. 31 * @cgrp: the cgroup in question 32 */ 33 static u64 debug_taskcount_read(struct cgroup_subsys_state *css, 34 struct cftype *cft) 35 { 36 return cgroup_task_count(css->cgroup); 37 } 38 39 static int current_css_set_read(struct seq_file *seq, void *v) 40 { 41 struct kernfs_open_file *of = seq->private; 42 struct css_set *cset; 43 struct cgroup_subsys *ss; 44 struct cgroup_subsys_state *css; 45 int i, refcnt; 46 47 if (!cgroup_kn_lock_live(of->kn, false)) 48 return -ENODEV; 49 50 spin_lock_irq(&css_set_lock); 51 rcu_read_lock(); 52 cset = rcu_dereference(current->cgroups); 53 refcnt = refcount_read(&cset->refcount); 54 seq_printf(seq, "css_set %pK %d", cset, refcnt); 55 if (refcnt > cset->nr_tasks) 56 seq_printf(seq, " +%d", refcnt - cset->nr_tasks); 57 seq_puts(seq, "\n"); 58 59 /* 60 * Print the css'es stored in the current css_set. 61 */ 62 for_each_subsys(ss, i) { 63 css = cset->subsys[ss->id]; 64 if (!css) 65 continue; 66 seq_printf(seq, "%2d: %-4s\t- %lx[%d]\n", ss->id, ss->name, 67 (unsigned long)css, css->id); 68 } 69 rcu_read_unlock(); 70 spin_unlock_irq(&css_set_lock); 71 cgroup_kn_unlock(of->kn); 72 return 0; 73 } 74 75 static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css, 76 struct cftype *cft) 77 { 78 u64 count; 79 80 rcu_read_lock(); 81 count = refcount_read(&task_css_set(current)->refcount); 82 rcu_read_unlock(); 83 return count; 84 } 85 86 static int current_css_set_cg_links_read(struct seq_file *seq, void *v) 87 { 88 struct cgrp_cset_link *link; 89 struct css_set *cset; 90 char *name_buf; 91 92 name_buf = kmalloc(NAME_MAX + 1, GFP_KERNEL); 93 if (!name_buf) 94 return -ENOMEM; 95 96 spin_lock_irq(&css_set_lock); 97 rcu_read_lock(); 98 cset = rcu_dereference(current->cgroups); 99 list_for_each_entry(link, &cset->cgrp_links, cgrp_link) { 100 struct cgroup *c = link->cgrp; 101 102 cgroup_name(c, name_buf, NAME_MAX + 1); 103 seq_printf(seq, "Root %d group %s\n", 104 c->root->hierarchy_id, name_buf); 105 } 106 rcu_read_unlock(); 107 spin_unlock_irq(&css_set_lock); 108 kfree(name_buf); 109 return 0; 110 } 111 112 #define MAX_TASKS_SHOWN_PER_CSS 25 113 static int cgroup_css_links_read(struct seq_file *seq, void *v) 114 { 115 struct cgroup_subsys_state *css = seq_css(seq); 116 struct cgrp_cset_link *link; 117 int dead_cnt = 0, extra_refs = 0; 118 119 spin_lock_irq(&css_set_lock); 120 list_for_each_entry(link, &css->cgroup->cset_links, cset_link) { 121 struct css_set *cset = link->cset; 122 struct task_struct *task; 123 int count = 0; 124 int refcnt = refcount_read(&cset->refcount); 125 126 seq_printf(seq, " %d", refcnt); 127 if (refcnt - cset->nr_tasks > 0) { 128 int extra = refcnt - cset->nr_tasks; 129 130 seq_printf(seq, " +%d", extra); 131 /* 132 * Take out the one additional reference in 133 * init_css_set. 134 */ 135 if (cset == &init_css_set) 136 extra--; 137 extra_refs += extra; 138 } 139 seq_puts(seq, "\n"); 140 141 list_for_each_entry(task, &cset->tasks, cg_list) { 142 if (count++ <= MAX_TASKS_SHOWN_PER_CSS) 143 seq_printf(seq, " task %d\n", 144 task_pid_vnr(task)); 145 } 146 147 list_for_each_entry(task, &cset->mg_tasks, cg_list) { 148 if (count++ <= MAX_TASKS_SHOWN_PER_CSS) 149 seq_printf(seq, " task %d\n", 150 task_pid_vnr(task)); 151 } 152 /* show # of overflowed tasks */ 153 if (count > MAX_TASKS_SHOWN_PER_CSS) 154 seq_printf(seq, " ... (%d)\n", 155 count - MAX_TASKS_SHOWN_PER_CSS); 156 157 if (cset->dead) { 158 seq_puts(seq, " [dead]\n"); 159 dead_cnt++; 160 } 161 162 WARN_ON(count != cset->nr_tasks); 163 } 164 spin_unlock_irq(&css_set_lock); 165 166 if (!dead_cnt && !extra_refs) 167 return 0; 168 169 seq_puts(seq, "\n"); 170 if (extra_refs) 171 seq_printf(seq, "extra references = %d\n", extra_refs); 172 if (dead_cnt) 173 seq_printf(seq, "dead css_sets = %d\n", dead_cnt); 174 175 return 0; 176 } 177 178 static int cgroup_subsys_states_read(struct seq_file *seq, void *v) 179 { 180 struct kernfs_open_file *of = seq->private; 181 struct cgroup *cgrp; 182 struct cgroup_subsys *ss; 183 struct cgroup_subsys_state *css; 184 char pbuf[16]; 185 int i; 186 187 cgrp = cgroup_kn_lock_live(of->kn, false); 188 if (!cgrp) 189 return -ENODEV; 190 191 for_each_subsys(ss, i) { 192 css = rcu_dereference_check(cgrp->subsys[ss->id], true); 193 if (!css) 194 continue; 195 196 pbuf[0] = '\0'; 197 198 /* Show the parent CSS if applicable*/ 199 if (css->parent) 200 snprintf(pbuf, sizeof(pbuf) - 1, " P=%d", 201 css->parent->id); 202 seq_printf(seq, "%2d: %-4s\t- %lx[%d] %d%s\n", ss->id, ss->name, 203 (unsigned long)css, css->id, 204 atomic_read(&css->online_cnt), pbuf); 205 } 206 207 cgroup_kn_unlock(of->kn); 208 return 0; 209 } 210 211 static void cgroup_masks_read_one(struct seq_file *seq, const char *name, 212 u16 mask) 213 { 214 struct cgroup_subsys *ss; 215 int ssid; 216 bool first = true; 217 218 seq_printf(seq, "%-17s: ", name); 219 for_each_subsys(ss, ssid) { 220 if (!(mask & (1 << ssid))) 221 continue; 222 if (!first) 223 seq_puts(seq, ", "); 224 seq_puts(seq, ss->name); 225 first = false; 226 } 227 seq_putc(seq, '\n'); 228 } 229 230 static int cgroup_masks_read(struct seq_file *seq, void *v) 231 { 232 struct kernfs_open_file *of = seq->private; 233 struct cgroup *cgrp; 234 235 cgrp = cgroup_kn_lock_live(of->kn, false); 236 if (!cgrp) 237 return -ENODEV; 238 239 cgroup_masks_read_one(seq, "subtree_control", cgrp->subtree_control); 240 cgroup_masks_read_one(seq, "subtree_ss_mask", cgrp->subtree_ss_mask); 241 242 cgroup_kn_unlock(of->kn); 243 return 0; 244 } 245 246 static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft) 247 { 248 return (!cgroup_is_populated(css->cgroup) && 249 !css_has_online_children(&css->cgroup->self)); 250 } 251 252 static struct cftype debug_legacy_files[] = { 253 { 254 .name = "taskcount", 255 .read_u64 = debug_taskcount_read, 256 }, 257 258 { 259 .name = "current_css_set", 260 .seq_show = current_css_set_read, 261 .flags = CFTYPE_ONLY_ON_ROOT, 262 }, 263 264 { 265 .name = "current_css_set_refcount", 266 .read_u64 = current_css_set_refcount_read, 267 .flags = CFTYPE_ONLY_ON_ROOT, 268 }, 269 270 { 271 .name = "current_css_set_cg_links", 272 .seq_show = current_css_set_cg_links_read, 273 .flags = CFTYPE_ONLY_ON_ROOT, 274 }, 275 276 { 277 .name = "cgroup_css_links", 278 .seq_show = cgroup_css_links_read, 279 }, 280 281 { 282 .name = "cgroup_subsys_states", 283 .seq_show = cgroup_subsys_states_read, 284 }, 285 286 { 287 .name = "cgroup_masks", 288 .seq_show = cgroup_masks_read, 289 }, 290 291 { 292 .name = "releasable", 293 .read_u64 = releasable_read, 294 }, 295 296 { } /* terminate */ 297 }; 298 299 static struct cftype debug_files[] = { 300 { 301 .name = "taskcount", 302 .read_u64 = debug_taskcount_read, 303 }, 304 305 { 306 .name = "current_css_set", 307 .seq_show = current_css_set_read, 308 .flags = CFTYPE_ONLY_ON_ROOT, 309 }, 310 311 { 312 .name = "current_css_set_refcount", 313 .read_u64 = current_css_set_refcount_read, 314 .flags = CFTYPE_ONLY_ON_ROOT, 315 }, 316 317 { 318 .name = "current_css_set_cg_links", 319 .seq_show = current_css_set_cg_links_read, 320 .flags = CFTYPE_ONLY_ON_ROOT, 321 }, 322 323 { 324 .name = "css_links", 325 .seq_show = cgroup_css_links_read, 326 }, 327 328 { 329 .name = "csses", 330 .seq_show = cgroup_subsys_states_read, 331 }, 332 333 { 334 .name = "masks", 335 .seq_show = cgroup_masks_read, 336 }, 337 338 { } /* terminate */ 339 }; 340 341 struct cgroup_subsys debug_cgrp_subsys = { 342 .css_alloc = debug_css_alloc, 343 .css_free = debug_css_free, 344 .legacy_cftypes = debug_legacy_files, 345 }; 346 347 /* 348 * On v2, debug is an implicit controller enabled by "cgroup_debug" boot 349 * parameter. 350 */ 351 static int __init enable_cgroup_debug(char *str) 352 { 353 debug_cgrp_subsys.dfl_cftypes = debug_files; 354 debug_cgrp_subsys.implicit_on_dfl = true; 355 return 1; 356 } 357 __setup("cgroup_debug", enable_cgroup_debug); 358