Initial version of a crash module which can be used to show which cgroups is the currently active process member of. --- Hello this is a simple crash extension that I hacked up over the weekend, in my case when I look at kernel crash dump I want to quickly understand which cgroup is the current process member of. Currently it uses the process from the current context but this might change in the future. Here is an example output: crash> show_cgroups subsys: cpuset cgroup: c6666 subsys: cpu cgroup: c6666 subsys: cpuacct cgroup: c6666 subsys: io cgroup: c6666 subsys: memory cgroup: c6666 subsys: devices cgroup: c6666 subsys: freezer cgroup: c6666 subsys: perf_event cgroup: c6666 subsys: pids cgroup: c6666 I have tested this on 4.6-rc2 with and without cgroup support enabled. I'm just sending this to get an initial idea whether I have used crash's facilities correctly and canvas for future ideas. I'm aware there are already 2 cgroup modules but when I tried running either they complained of no cgroup support or the command did nothing. In any case provided that the code is ok I guess this can be used as a good example of how to traverse structures with crash TODO: * Make the command understand either task_struct pointer or pid being passed. * Add support for pre-3.15 kernels (the cgroup name struct changed to kernfs at that point) * Whatever people think might be useful extensions/proccgroup.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 extensions/proccgroup.c diff --git a/extensions/proccgroup.c b/extensions/proccgroup.c new file mode 100644 index 0000000..fceeaf6 --- /dev/null +++ b/extensions/proccgroup.c @@ -0,0 +1,136 @@ +/* + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Nikolay Borisov <n.borisov.lkml@xxxxxxxxx> + */ + +#include "defs.h" + +#define CGROUP_PATH_MAX +void proccgroup_init(void); +void proccgroup_fini(void); + +void show_proc_cgroups(void); +char *help_proc_cgroups[]; + +static struct command_table_entry command_table[] = { + { "show_cgroups", show_proc_cgroups, help_proc_cgroups, 0}, + { NULL }, +}; + + +void __attribute__((constructor)) +echo_init(void) +{ + register_extension(command_table); +} + +void __attribute__((destructor)) +echo_fini(void) { } + + +static void get_cgroup_name(ulong cgroup, char *buf, size_t buflen) +{ + + ulong kernfs_node; + ulong cgroup_name_ptr; + ulong kernfs_parent; + + /* Get cgroup->kn */ + readmem(cgroup + MEMBER_OFFSET("cgroup", "kn"), KVADDR, &kernfs_node, sizeof(void *), + "cgroup->kn", RETURN_ON_ERROR); + + readmem(kernfs_node + MEMBER_OFFSET("kernfs_node", "parent"), KVADDR, &kernfs_parent, sizeof(void *), + "kernfs_node->parent", RETURN_ON_ERROR); + + if (kernfs_parent == 0) { + sprintf(buf, "/"); + return; + } + + /* Get kn->name */ + readmem(kernfs_node + MEMBER_OFFSET("kernfs_node", "name"), KVADDR, &cgroup_name_ptr, sizeof(void *), + "kernfs_node->name", RETURN_ON_ERROR); + + read_string(cgroup_name_ptr, buf, buflen-1); +} + + +static void get_subsys_name(ulong subsys, char *buf, size_t buflen) +{ + + ulong subsys_name_ptr; + ulong cgroup_subsys_ptr; + + /* Get cgroup->kn */ + readmem(subsys + MEMBER_OFFSET("cgroup_subsys_state", "ss"), KVADDR, &cgroup_subsys_ptr, sizeof(void *), + "cgroup_subsys_state->ss", RETURN_ON_ERROR); + + readmem(cgroup_subsys_ptr + MEMBER_OFFSET("cgroup_subsys", "name"), KVADDR, &subsys_name_ptr, sizeof(void *), + "cgroup_subsys->name", RETURN_ON_ERROR); + read_string(subsys_name_ptr, buf, buflen-1); +} + +static void get_kn_cgroup_name(ulong cgroup, ulong subsys) +{ + + char cgroup_name[BUFSIZE]; + char subsys_name[BUFSIZE]; + + get_cgroup_name(cgroup, cgroup_name, BUFSIZE); + get_subsys_name(subsys, subsys_name, BUFSIZE); + + fprintf(fp, "subsys: %-20s cgroup: %s\n", subsys_name, cgroup_name); +} + +void +show_proc_cgroups(void) +{ + ulong cgroups_subsys_ptr = 0; + int subsyscount; + int i; + + if (!MEMBER_EXISTS("task_struct", "cgroups")) { + fprintf(fp, "No cgroup support found\n"); + return; + } + + /* Get address of task_struct->cgroups */ + readmem(CURRENT_TASK() + MEMBER_OFFSET("task_struct", "cgroups"), + KVADDR, &cgroups_subsys_ptr, sizeof(void *), + "task_struct->cgroups", RETURN_ON_ERROR); + + subsyscount = MEMBER_SIZE("css_set", "subsys") / sizeof(void *); + + for (i = 0; i < subsyscount; i++) { + ulong subsys_ptr; + ulong subsys_base = cgroups_subsys_ptr + MEMBER_OFFSET("css_set", "subsys"); + ulong cgroup; + + /* Get css_set->subsys[i] address */ + readmem(subsys_base + (i * sizeof(void*)), KVADDR, &subsys_ptr, sizeof(void *), + "css_set->subsys[i]", RETURN_ON_ERROR); + /* Get cgroup_subsys_state -> cgroup */ + readmem(subsys_ptr + MEMBER_OFFSET("cgroup_subsys_state", "cgroup"), KVADDR, &cgroup, sizeof(void *), + "cgroup_subsys_state->cgroup", RETURN_ON_ERROR); + + /* Handle the 2 cases of cgroup_name and the kernfs one */ + if (MEMBER_EXISTS("cgroup", "kn")) { + get_kn_cgroup_name(cgroup, subsys_ptr); + } else if (MEMBER_EXISTS("cgroup", "name")) { + fprintf(fp, "Unsupported kernel version"); + } + } +} + +char *help_proc_cgroups[] = { + "show_cgroup", /* command name */ + "Show which cgroups is the current process member of", /* short description */ + " ", /* argument synopsis, or " " if none */ + NULL +}; + + -- 2.5.0 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility