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(a)gmail.com>
+ */
+
+#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